From dc8cfa55da8c21e0b3290c29677a9d05c0a3e595 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 1 Sep 2008 12:46:50 +0100 Subject: sfc: Use explicit bool for boolean variables, parameters and return values Replace (cond ? 1 : 0) with cond or !!cond as appropriate, and (cond ? 0 : 1) with !cond. Remove some redundant boolean temporaries. Rename one field that looks like a flag but isn't. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/falcon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/sfc/falcon.h') diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 492f9bc2884..a72f50e3e6e 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -65,7 +65,7 @@ extern int falcon_probe_port(struct efx_nic *efx); extern void falcon_remove_port(struct efx_nic *efx); /* MAC/PHY */ -extern int falcon_xaui_link_ok(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); -- cgit v1.2.3-70-g09d2 From 42cbe2d73c9bc2574f86d63c2b57da93e3b3060d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 1 Sep 2008 12:48:08 +0100 Subject: sfc: Cleanup RX event processing Make efx_process_channel() and falcon_process_eventq() return the number of packets received rather than updating the quota, consistent with new NAPI. Since channels and RX queues are mapped one-to-one, remove return value from falcon_handle_rx_event() and add a warning for events with the wrong RX queue number. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/efx.c | 27 ++++++++++----------------- drivers/net/sfc/falcon.c | 30 ++++++++++++------------------ drivers/net/sfc/falcon.h | 2 +- 3 files changed, 23 insertions(+), 36 deletions(-) (limited to 'drivers/net/sfc/falcon.h') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 22004a612d2..864095ea5b3 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -160,14 +160,16 @@ static void efx_fini_channels(struct efx_nic *efx); */ static int efx_process_channel(struct efx_channel *channel, int rx_quota) { - int rxdmaqs; - struct efx_rx_queue *rx_queue; + struct efx_nic *efx = channel->efx; + int rx_packets; - if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE || + if (unlikely(efx->reset_pending != RESET_TYPE_NONE || !channel->enabled)) - return rx_quota; + return 0; - rxdmaqs = falcon_process_eventq(channel, &rx_quota); + rx_packets = falcon_process_eventq(channel, rx_quota); + if (rx_packets == 0) + return 0; /* Deliver last RX packet. */ if (channel->rx_pkt) { @@ -179,16 +181,9 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) efx_flush_lro(channel); efx_rx_strategy(channel); - /* Refill descriptor rings as necessary */ - rx_queue = &channel->efx->rx_queue[0]; - while (rxdmaqs) { - if (rxdmaqs & 0x01) - efx_fast_push_rx_descriptors(rx_queue); - rx_queue++; - rxdmaqs >>= 1; - } + efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]); - return rx_quota; + return rx_packets; } /* Mark channel as finished processing @@ -218,14 +213,12 @@ static int efx_poll(struct napi_struct *napi, int budget) struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); struct net_device *napi_dev = channel->napi_dev; - int unused; int rx_packets; EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", channel->channel, raw_smp_processor_id()); - unused = efx_process_channel(channel, budget); - rx_packets = (budget - unused); + rx_packets = efx_process_channel(channel, budget); if (rx_packets < budget) { /* There is no race here; although napi_disable() will diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 7b1c387ff8e..96cb5d031ed 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -952,10 +952,10 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, * Also "is multicast" and "matches multicast filter" flags can be used to * discard non-matching multicast packets. */ -static int falcon_handle_rx_event(struct efx_channel *channel, - const efx_qword_t *event) +static void falcon_handle_rx_event(struct efx_channel *channel, + const efx_qword_t *event) { - unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt; + unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; unsigned expected_ptr; bool rx_ev_pkt_ok, discard = false, checksummed; @@ -968,16 +968,14 @@ static int falcon_handle_rx_event(struct efx_channel *channel, rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT)); WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1); + WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel); - rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL); - rx_queue = &efx->rx_queue[rx_ev_q_label]; + rx_queue = &efx->rx_queue[channel->channel]; rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR); expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK; - if (unlikely(rx_ev_desc_ptr != expected_ptr)) { + if (unlikely(rx_ev_desc_ptr != expected_ptr)) falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); - return rx_ev_q_label; - } if (likely(rx_ev_pkt_ok)) { /* If packet is marked as OK and packet type is TCP/IPv4 or @@ -1003,8 +1001,6 @@ static int falcon_handle_rx_event(struct efx_channel *channel, /* Handle received packet */ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, checksummed, discard); - - return rx_ev_q_label; } /* Global events are basically PHY events */ @@ -1109,13 +1105,12 @@ static void falcon_handle_driver_event(struct efx_channel *channel, } } -int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) +int falcon_process_eventq(struct efx_channel *channel, int rx_quota) { unsigned int read_ptr; efx_qword_t event, *p_event; int ev_code; - int rxq; - int rxdmaqs = 0; + int rx_packets = 0; read_ptr = channel->eventq_read_ptr; @@ -1137,9 +1132,8 @@ int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) switch (ev_code) { case RX_IP_EV_DECODE: - rxq = falcon_handle_rx_event(channel, &event); - rxdmaqs |= (1 << rxq); - (*rx_quota)--; + falcon_handle_rx_event(channel, &event); + ++rx_packets; break; case TX_IP_EV_DECODE: falcon_handle_tx_event(channel, &event); @@ -1166,10 +1160,10 @@ int falcon_process_eventq(struct efx_channel *channel, int *rx_quota) /* Increment read pointer */ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } while (*rx_quota); + } while (rx_packets < rx_quota); channel->eventq_read_ptr = read_ptr; - return rxdmaqs; + return rx_packets; } void falcon_set_int_moderation(struct efx_channel *channel) diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index a72f50e3e6e..4cf05d0b5cf 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -57,7 +57,7 @@ extern int falcon_probe_eventq(struct efx_channel *channel); extern int falcon_init_eventq(struct efx_channel *channel); extern void falcon_fini_eventq(struct efx_channel *channel); extern void falcon_remove_eventq(struct efx_channel *channel); -extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota); +extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); extern void falcon_eventq_read_ack(struct efx_channel *channel); /* Ports */ -- cgit v1.2.3-70-g09d2 From bc3c90a2b70652b87cde8de65275d6f41d0f24c3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 1 Sep 2008 12:48:46 +0100 Subject: sfc: Remove some unreachable error paths Some functions return an error code which is always 0. Change their return types to void and simplify their callers accordingly. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/efx.c | 76 +++++++++++------------------------------------ drivers/net/sfc/efx.h | 2 +- drivers/net/sfc/ethtool.c | 8 ++--- drivers/net/sfc/falcon.c | 30 +++++-------------- drivers/net/sfc/falcon.h | 6 ++-- drivers/net/sfc/rx.c | 4 +-- drivers/net/sfc/rx.h | 2 +- drivers/net/sfc/tx.c | 4 +-- drivers/net/sfc/tx.h | 2 +- 9 files changed, 39 insertions(+), 95 deletions(-) (limited to 'drivers/net/sfc/falcon.h') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index c41035a9938..f226dcf18c7 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -282,13 +282,13 @@ static int efx_probe_eventq(struct efx_channel *channel) } /* Prepare channel's event queue */ -static int efx_init_eventq(struct efx_channel *channel) +static void efx_init_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel); channel->eventq_read_ptr = 0; - return falcon_init_eventq(channel); + falcon_init_eventq(channel); } static void efx_fini_eventq(struct efx_channel *channel) @@ -354,12 +354,11 @@ static int efx_probe_channel(struct efx_channel *channel) * to propagate configuration changes (mtu, checksum offload), or * to clear hardware error conditions */ -static int efx_init_channels(struct efx_nic *efx) +static void efx_init_channels(struct efx_nic *efx) { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; struct efx_channel *channel; - int rc = 0; /* Calculate the rx buffer allocation parameters required to * support the current MTU, including padding for header @@ -374,36 +373,20 @@ static int efx_init_channels(struct efx_nic *efx) efx_for_each_channel(channel, efx) { EFX_LOG(channel->efx, "init chan %d\n", channel->channel); - rc = efx_init_eventq(channel); - if (rc) - goto err; + efx_init_eventq(channel); - efx_for_each_channel_tx_queue(tx_queue, channel) { - rc = efx_init_tx_queue(tx_queue); - if (rc) - goto err; - } + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue(tx_queue); /* The rx buffer allocation strategy is MTU dependent */ efx_rx_strategy(channel); - efx_for_each_channel_rx_queue(rx_queue, channel) { - rc = efx_init_rx_queue(rx_queue); - if (rc) - goto err; - } + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_init_rx_queue(rx_queue); WARN_ON(channel->rx_pkt != NULL); efx_rx_strategy(channel); } - - return 0; - - err: - EFX_ERR(efx, "failed to initialise channel %d\n", - channel ? channel->channel : -1); - efx_fini_channels(efx); - return rc; } /* This enables event queue processing and packet transmission. @@ -1121,24 +1104,16 @@ static void efx_remove_all(struct efx_nic *efx) } /* A convinience function to safely flush all the queues */ -int efx_flush_queues(struct efx_nic *efx) +void efx_flush_queues(struct efx_nic *efx) { - int rc; - EFX_ASSERT_RESET_SERIALISED(efx); efx_stop_all(efx); efx_fini_channels(efx); - rc = efx_init_channels(efx); - if (rc) { - efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; - } + efx_init_channels(efx); efx_start_all(efx); - - return 0; } /************************************************************************** @@ -1311,7 +1286,6 @@ static int efx_net_open(struct net_device *net_dev) static int efx_net_stop(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - int rc; EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); @@ -1319,9 +1293,7 @@ static int efx_net_stop(struct net_device *net_dev) /* Stop the device and flush all the channels */ efx_stop_all(efx); efx_fini_channels(efx); - rc = efx_init_channels(efx); - if (rc) - efx_schedule_reset(efx, RESET_TYPE_DISABLE); + efx_init_channels(efx); return 0; } @@ -1404,16 +1376,10 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) efx_fini_channels(efx); net_dev->mtu = new_mtu; - rc = efx_init_channels(efx); - if (rc) - goto fail; + efx_init_channels(efx); efx_start_all(efx); return rc; - - fail: - efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; } static int efx_set_mac_address(struct net_device *net_dev, void *data) @@ -1588,22 +1554,19 @@ static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd) { int rc; - rc = efx_init_channels(efx); - if (rc) - goto fail1; + efx_init_channels(efx); /* Restore MAC and PHY settings. */ rc = falcon_xmac_set_settings(efx, ecmd); if (rc) { EFX_ERR(efx, "could not restore PHY settings\n"); - goto fail2; + goto fail; } return 0; - fail2: + fail: efx_fini_channels(efx); - fail1: return rc; } @@ -2023,19 +1986,16 @@ static int efx_pci_probe_main(struct efx_nic *efx) goto fail5; } - rc = efx_init_channels(efx); - if (rc) - goto fail6; + efx_init_channels(efx); rc = falcon_init_interrupt(efx); if (rc) - goto fail7; + goto fail6; return 0; - fail7: - efx_fini_channels(efx); fail6: + efx_fini_channels(efx); efx_fini_port(efx); fail5: fail4: diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 29a1c583058..9a8c283fa88 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -33,7 +33,7 @@ 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 int efx_flush_queues(struct efx_nic *efx); +extern void efx_flush_queues(struct efx_nic *efx); /* Ports */ extern void efx_reconfigure_port(struct efx_nic *efx); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 906d18a6526..79894160a9a 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -503,10 +503,10 @@ static void efx_ethtool_self_test(struct net_device *net_dev, if (offline) { /* Stop the kernel from sending packets during the test. */ efx_stop_queue(efx); - rc = efx_flush_queues(efx); - if (!rc) - rc = efx_offline_test(efx, &efx_tests, - efx->loopback_modes); + efx_flush_queues(efx); + + rc = efx_offline_test(efx, &efx_tests, + efx->loopback_modes); efx_wake_queue(efx); } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 96cb5d031ed..e66d6cf03ad 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -242,7 +242,7 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing * it to be used for event queues, descriptor rings etc. */ -static int +static void falcon_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) { @@ -266,8 +266,6 @@ falcon_init_special_buffer(struct efx_nic *efx, BUF_OWNER_ID_FBUF, 0); falcon_write_sram(efx, &buf_desc, index); } - - return 0; } /* Unmaps a buffer from Falcon and clears the buffer table entries */ @@ -449,16 +447,13 @@ int falcon_probe_tx(struct efx_tx_queue *tx_queue) sizeof(efx_qword_t)); } -int falcon_init_tx(struct efx_tx_queue *tx_queue) +void falcon_init_tx(struct efx_tx_queue *tx_queue) { efx_oword_t tx_desc_ptr; struct efx_nic *efx = tx_queue->efx; - int rc; /* Pin TX descriptor ring */ - rc = falcon_init_special_buffer(efx, &tx_queue->txd); - if (rc) - return rc; + falcon_init_special_buffer(efx, &tx_queue->txd); /* Push TX descriptor ring to card */ EFX_POPULATE_OWORD_10(tx_desc_ptr, @@ -495,8 +490,6 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue) set_bit_le(tx_queue->queue, (void *)®); falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1); } - - return 0; } static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) @@ -639,11 +632,10 @@ int falcon_probe_rx(struct efx_rx_queue *rx_queue) sizeof(efx_qword_t)); } -int falcon_init_rx(struct efx_rx_queue *rx_queue) +void falcon_init_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; - int rc; bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; bool iscsi_digest_en = is_b0; @@ -652,9 +644,7 @@ int falcon_init_rx(struct efx_rx_queue *rx_queue) rx_queue->rxd.index + rx_queue->rxd.entries - 1); /* Pin RX descriptor ring */ - rc = falcon_init_special_buffer(efx, &rx_queue->rxd); - if (rc) - return rc; + falcon_init_special_buffer(efx, &rx_queue->rxd); /* Push RX descriptor ring to card */ EFX_POPULATE_OWORD_10(rx_desc_ptr, @@ -671,7 +661,6 @@ int falcon_init_rx(struct efx_rx_queue *rx_queue) RX_DESCQ_EN, 1); falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, rx_queue->queue); - return 0; } static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) @@ -1205,20 +1194,17 @@ int falcon_probe_eventq(struct efx_channel *channel) return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); } -int falcon_init_eventq(struct efx_channel *channel) +void falcon_init_eventq(struct efx_channel *channel) { efx_oword_t evq_ptr; struct efx_nic *efx = channel->efx; - int rc; EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", channel->channel, channel->eventq.index, channel->eventq.index + channel->eventq.entries - 1); /* Pin event queue buffer */ - rc = falcon_init_special_buffer(efx, &channel->eventq); - if (rc) - return rc; + falcon_init_special_buffer(efx, &channel->eventq); /* Fill event queue with all ones (i.e. empty events) */ memset(channel->eventq.addr, 0xff, channel->eventq.len); @@ -1232,8 +1218,6 @@ int falcon_init_eventq(struct efx_channel *channel) channel->channel); falcon_set_int_moderation(channel); - - return 0; } void falcon_fini_eventq(struct efx_channel *channel) diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 4cf05d0b5cf..41b388b6599 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -40,21 +40,21 @@ extern struct efx_nic_type falcon_b_nic_type; /* TX data path */ extern int falcon_probe_tx(struct efx_tx_queue *tx_queue); -extern int falcon_init_tx(struct efx_tx_queue *tx_queue); +extern void falcon_init_tx(struct efx_tx_queue *tx_queue); extern void falcon_fini_tx(struct efx_tx_queue *tx_queue); extern void falcon_remove_tx(struct efx_tx_queue *tx_queue); extern void falcon_push_buffers(struct efx_tx_queue *tx_queue); /* RX data path */ extern int falcon_probe_rx(struct efx_rx_queue *rx_queue); -extern int falcon_init_rx(struct efx_rx_queue *rx_queue); +extern void falcon_init_rx(struct efx_rx_queue *rx_queue); extern void falcon_fini_rx(struct efx_rx_queue *rx_queue); extern void falcon_remove_rx(struct efx_rx_queue *rx_queue); extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue); /* Event data path */ extern int falcon_probe_eventq(struct efx_channel *channel); -extern int falcon_init_eventq(struct efx_channel *channel); +extern void falcon_init_eventq(struct efx_channel *channel); extern void falcon_fini_eventq(struct efx_channel *channel); extern void falcon_remove_eventq(struct efx_channel *channel); extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 7d2dc20d0ca..0f805da4ce5 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -800,7 +800,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) return rc; } -int efx_init_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; @@ -824,7 +824,7 @@ int efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ - return falcon_init_rx(rx_queue); + falcon_init_rx(rx_queue); } void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h index 187b1109973..0e88a9ddc1c 100644 --- a/drivers/net/sfc/rx.h +++ b/drivers/net/sfc/rx.h @@ -14,7 +14,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); -int efx_init_rx_queue(struct efx_rx_queue *rx_queue); +void efx_init_rx_queue(struct efx_rx_queue *rx_queue); void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx); diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index a3a3eddd30b..cdee7c200d6 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -443,7 +443,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) return rc; } -int efx_init_tx_queue(struct efx_tx_queue *tx_queue) +void efx_init_tx_queue(struct efx_tx_queue *tx_queue) { EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue); @@ -454,7 +454,7 @@ int efx_init_tx_queue(struct efx_tx_queue *tx_queue) BUG_ON(tx_queue->stopped); /* Set up TX descriptor ring */ - return falcon_init_tx(tx_queue); + falcon_init_tx(tx_queue); } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h index 1526a73b4b5..5e1cc234e42 100644 --- a/drivers/net/sfc/tx.h +++ b/drivers/net/sfc/tx.h @@ -15,7 +15,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); -int efx_init_tx_queue(struct efx_tx_queue *tx_queue); +void efx_init_tx_queue(struct efx_tx_queue *tx_queue); void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); -- cgit v1.2.3-70-g09d2 From 8c8661e4cefdd1ddbfe7d5120f046694555d9e5c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 1 Sep 2008 12:49:02 +0100 Subject: sfc: Extend self-tests Include PMA/PMD in loopback self-tests as intended. Add NVRAM checksum validation and include it in self-tests. Add register self-tests. Run PHY self-tests where available. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/bitfield.h | 19 ++- drivers/net/sfc/efx.c | 20 ++- drivers/net/sfc/efx.h | 6 + drivers/net/sfc/ethtool.c | 22 ++-- drivers/net/sfc/falcon.c | 198 ++++++++++++++++++++++++---- drivers/net/sfc/falcon.h | 6 + drivers/net/sfc/falcon_hwdefs.h | 4 +- drivers/net/sfc/falcon_xmac.c | 14 +- drivers/net/sfc/net_driver.h | 16 ++- drivers/net/sfc/selftest.c | 277 ++++++++++++++++++++++++---------------- drivers/net/sfc/selftest.h | 9 +- drivers/net/sfc/tenxpress.c | 22 +--- 12 files changed, 429 insertions(+), 184 deletions(-) (limited to 'drivers/net/sfc/falcon.h') diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index b757a39f078..d95c2182801 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h @@ -416,12 +416,23 @@ typedef union efx_oword { * for read-modify-write operations. * */ - #define EFX_INVERT_OWORD(oword) do { \ (oword).u64[0] = ~((oword).u64[0]); \ (oword).u64[1] = ~((oword).u64[1]); \ } while (0) +#define EFX_AND_OWORD(oword, from, mask) \ + do { \ + (oword).u64[0] = (from).u64[0] & (mask).u64[0]; \ + (oword).u64[1] = (from).u64[1] & (mask).u64[1]; \ + } while (0) + +#define EFX_OR_OWORD(oword, from, mask) \ + do { \ + (oword).u64[0] = (from).u64[0] | (mask).u64[0]; \ + (oword).u64[1] = (from).u64[1] | (mask).u64[1]; \ + } while (0) + #define EFX_INSERT64(min, max, low, high, value) \ cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value)) @@ -529,4 +540,10 @@ typedef union efx_oword { #define EFX_DMA_TYPE_WIDTH(width) \ (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH) + +/* Static initialiser */ +#define EFX_OWORD32(a, b, c, d) \ + { .u32 = { __constant_cpu_to_le32(a), __constant_cpu_to_le32(b), \ + __constant_cpu_to_le32(c), __constant_cpu_to_le32(d) } } + #endif /* EFX_BITFIELD_H */ diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f34dbf2c5b6..e1e2f806056 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -508,6 +508,11 @@ static void efx_link_status_changed(struct efx_nic *efx) if (!netif_running(efx->net_dev)) return; + if (efx->port_inhibited) { + netif_carrier_off(efx->net_dev); + return; + } + if (efx->link_up != netif_carrier_ok(efx->net_dev)) { efx->n_link_state_changes++; @@ -549,7 +554,7 @@ static void efx_link_status_changed(struct efx_nic *efx) /* This call reinitialises the MAC to pick up new PHY settings. The * caller must hold the mac_lock */ -static void __efx_reconfigure_port(struct efx_nic *efx) +void __efx_reconfigure_port(struct efx_nic *efx) { WARN_ON(!mutex_is_locked(&efx->mac_lock)); @@ -634,6 +639,7 @@ static int efx_init_port(struct efx_nic *efx) return rc; efx->port_initialized = true; + efx->stats_enabled = true; /* Reconfigure port to program MAC registers */ falcon_reconfigure_xmac(efx); @@ -1311,7 +1317,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) */ if (!spin_trylock(&efx->stats_lock)) return stats; - if (efx->state == STATE_RUNNING) { + if (efx->stats_enabled) { falcon_update_stats_xmac(efx); falcon_update_nic_stats(efx); } @@ -1529,7 +1535,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) /* Tears down the entire software state and most of the hardware state * before reset. */ -static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) { int rc; @@ -1538,6 +1544,7 @@ static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) /* The net_dev->get_stats handler is quite slow, and will fail * if a fetch is pending over reset. Serialise against it. */ spin_lock(&efx->stats_lock); + efx->stats_enabled = false; spin_unlock(&efx->stats_lock); efx_stop_all(efx); @@ -1555,8 +1562,7 @@ static void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) * that we were unable to reinitialise the hardware, and the * driver should be disabled. If ok is false, then the rx and tx * engines are not restarted, pending a RESET_DISABLE. */ -static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, - bool ok) +int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) { int rc; @@ -1577,8 +1583,10 @@ static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, mutex_unlock(&efx->mac_lock); - if (ok) + if (ok) { efx_start_all(efx); + efx->stats_enabled = true; + } return rc; } diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 9a8c283fa88..d02937b70ee 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -37,6 +37,12 @@ extern void efx_flush_queues(struct efx_nic *efx); /* Ports */ extern void efx_reconfigure_port(struct efx_nic *efx); +extern void __efx_reconfigure_port(struct efx_nic *efx); + +/* Reset handling */ +extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd); +extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, + bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 79894160a9a..fa98af58223 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -333,7 +333,10 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, unsigned int n = 0; enum efx_loopback_mode mode; - /* Interrupt */ + efx_fill_test(n++, strings, data, &tests->mii, + "core", 0, "mii", NULL); + efx_fill_test(n++, strings, data, &tests->nvram, + "core", 0, "nvram", NULL); efx_fill_test(n++, strings, data, &tests->interrupt, "core", 0, "interrupt", NULL); @@ -353,16 +356,17 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, "eventq.poll", NULL); } - /* PHY presence */ - efx_fill_test(n++, strings, data, &tests->phy_ok, - EFX_PORT_NAME, "phy_ok", NULL); + efx_fill_test(n++, strings, data, &tests->registers, + "core", 0, "registers", NULL); + efx_fill_test(n++, strings, data, &tests->phy, + EFX_PORT_NAME, "phy", NULL); /* Loopback tests */ efx_fill_test(n++, strings, data, &tests->loopback_speed, EFX_PORT_NAME, "loopback.speed", NULL); efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, EFX_PORT_NAME, "loopback.full_duplex", NULL); - for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { + for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(efx->loopback_modes & (1 << mode))) continue; n = efx_fill_loopback_test(efx, @@ -500,15 +504,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev, goto out; /* Perform offline tests only if online tests passed */ - if (offline) { - /* Stop the kernel from sending packets during the test. */ - efx_stop_queue(efx); - efx_flush_queues(efx); - + if (offline) rc = efx_offline_test(efx, &efx_tests, efx->loopback_modes); - efx_wake_queue(efx); - } out: if (!already_up) diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index e66d6cf03ad..e0c0b23f94e 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2223,6 +2223,170 @@ void falcon_set_multicast_hash(struct efx_nic *efx) falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); } + +/************************************************************************** + * + * Falcon test code + * + **************************************************************************/ + +int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) +{ + struct falcon_nvconfig *nvconfig; + struct efx_spi_device *spi; + void *region; + int rc, magic_num, struct_ver; + __le16 *word, *limit; + u32 csum; + + region = kmalloc(NVCONFIG_END, GFP_KERNEL); + if (!region) + return -ENOMEM; + nvconfig = region + NVCONFIG_OFFSET; + + spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; + rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region); + if (rc) { + EFX_ERR(efx, "Failed to read %s\n", + efx->spi_flash ? "flash" : "EEPROM"); + rc = -EIO; + goto out; + } + + magic_num = le16_to_cpu(nvconfig->board_magic_num); + struct_ver = le16_to_cpu(nvconfig->board_struct_ver); + + rc = -EINVAL; + if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) { + EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num); + goto out; + } + if (struct_ver < 2) { + EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver); + goto out; + } else if (struct_ver < 4) { + word = &nvconfig->board_magic_num; + limit = (__le16 *) (nvconfig + 1); + } else { + word = region; + limit = region + NVCONFIG_END; + } + for (csum = 0; word < limit; ++word) + csum += le16_to_cpu(*word); + + if (~csum & 0xffff) { + EFX_ERR(efx, "NVRAM has incorrect checksum\n"); + goto out; + } + + rc = 0; + if (nvconfig_out) + memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig)); + + out: + kfree(region); + return rc; +} + +/* Registers tested in the falcon register test */ +static struct { + unsigned address; + efx_oword_t mask; +} efx_test_registers[] = { + { ADR_REGION_REG_KER, + EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, + { RX_CFG_REG_KER, + EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, + { TX_CFG_REG_KER, + EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, + { TX_CFG2_REG_KER, + EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, + { MAC0_CTRL_REG_KER, + EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, + { SRM_TX_DC_CFG_REG_KER, + EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { RX_DC_CFG_REG_KER, + EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, + { RX_DC_PF_WM_REG_KER, + EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, + { DP_CTRL_REG, + EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { XM_GLB_CFG_REG, + EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, + { XM_TX_CFG_REG, + EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, + { XM_RX_CFG_REG, + EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, + { XM_RX_PARAM_REG, + EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, + { XM_FC_REG, + EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, + { XM_ADR_LO_REG, + EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { XX_SD_CTL_REG, + EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, +}; + +static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, + const efx_oword_t *mask) +{ + return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || + ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); +} + +int falcon_test_registers(struct efx_nic *efx) +{ + unsigned address = 0, i, j; + efx_oword_t mask, imask, original, reg, buf; + + /* Falcon should be in loopback to isolate the XMAC from the PHY */ + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { + address = efx_test_registers[i].address; + mask = imask = efx_test_registers[i].mask; + EFX_INVERT_OWORD(imask); + + falcon_read(efx, &original, address); + + /* bit sweep on and off */ + for (j = 0; j < 128; j++) { + if (!EFX_EXTRACT_OWORD32(mask, j, j)) + continue; + + /* Test this testable bit can be set in isolation */ + EFX_AND_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 1); + + falcon_write(efx, ®, address); + falcon_read(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + + /* Test this testable bit can be cleared in isolation */ + EFX_OR_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 0); + + falcon_write(efx, ®, address); + falcon_read(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + } + + falcon_write(efx, &original, address); + } + + return 0; + +fail: + EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT + " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), + EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); + return -EIO; +} + /************************************************************************** * * Device reset @@ -2404,37 +2568,22 @@ static void falcon_remove_spi_devices(struct efx_nic *efx) static int falcon_probe_nvconfig(struct efx_nic *efx) { struct falcon_nvconfig *nvconfig; - struct efx_spi_device *spi; - int magic_num, struct_ver, board_rev; + int board_rev; int rc; nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL); if (!nvconfig) return -ENOMEM; - /* Read the whole configuration structure into memory. */ - spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; - rc = falcon_spi_read(spi, NVCONFIG_BASE, sizeof(*nvconfig), - NULL, (char *)nvconfig); - if (rc) { - EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" : - "EEPROM"); - goto fail1; - } - - /* Read the MAC addresses */ - memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); - - /* Read the board configuration. */ - magic_num = le16_to_cpu(nvconfig->board_magic_num); - struct_ver = le16_to_cpu(nvconfig->board_struct_ver); - - if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) { - EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x " - "therefore using defaults\n", magic_num, struct_ver); + rc = falcon_read_nvram(efx, nvconfig); + if (rc == -EINVAL) { + EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); efx->phy_type = PHY_TYPE_NONE; efx->mii.phy_id = PHY_ADDR_INVALID; board_rev = 0; + rc = 0; + } else if (rc) { + goto fail1; } else { struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; @@ -2443,7 +2592,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) efx->mii.phy_id = v2->port0_phy_addr; board_rev = le16_to_cpu(v2->board_revision); - if (struct_ver >= 3) { + if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; rc = falcon_spi_device_init(efx, &efx->spi_flash, @@ -2459,6 +2608,9 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) } } + /* Read the MAC addresses */ + memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); + EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); efx_set_board_info(efx, board_rev); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 41b388b6599..30d61e48ac6 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -93,6 +93,12 @@ extern void falcon_update_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); +/* Tests */ +struct falcon_nvconfig; +extern int falcon_read_nvram(struct efx_nic *efx, + struct falcon_nvconfig *nvconfig); +extern int falcon_test_registers(struct efx_nic *efx); + /************************************************************************** * * Falcon MAC stats diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index a3260dfb49a..e319fd64d07 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -1150,7 +1150,9 @@ struct falcon_nvconfig_board_v3 { #define SPI_DEV_TYPE_FIELD(type, field) \ (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) -#define NVCONFIG_BASE 0x300 +#define NVCONFIG_OFFSET 0x300 +#define NVCONFIG_END 0x400 + #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C struct falcon_nvconfig { efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index a9ae06a2ae2..0d9f68ff71e 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -373,17 +373,9 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || (xaui_loopback != old_xaui_loopback) || (xgmii_loopback != old_xgmii_loopback)); - if (reset_xgxs) { - falcon_read(efx, ®, XX_PWR_RST_REG); - EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1); - EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1); - falcon_write(efx, ®, XX_PWR_RST_REG); - udelay(1); - EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0); - EFX_SET_OWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0); - falcon_write(efx, ®, XX_PWR_RST_REG); - udelay(1); - } + + if (reset_xgxs) + falcon_reset_xaui(efx); } falcon_read(efx, ®, XX_CORE_STAT_REG); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index df863bcc06f..531d939b574 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -515,6 +515,7 @@ struct efx_phy_operations { void (*clear_interrupt) (struct efx_nic *efx); int (*check_hw) (struct efx_nic *efx); void (*reset_xaui) (struct efx_nic *efx); + int (*test) (struct efx_nic *efx); int mmds; unsigned loopbacks; }; @@ -533,7 +534,7 @@ enum efx_phy_mode { static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode) { - return (mode & ~PHY_MODE_TX_DISABLED) != 0; + return !!(mode & ~PHY_MODE_TX_DISABLED); } /* @@ -655,13 +656,14 @@ union efx_multicast_hash { * This field will be %NULL if no EEPROM device is present. * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state - * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and - * efx_reconfigure_port() + * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, + * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and * efx_reconfigure_work with kernel interfaces. Safe to read under any * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must * be held to modify it. + * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock * @rx_checksum_enabled: RX checksumming enabled @@ -671,14 +673,16 @@ union efx_multicast_hash { * can provide. Generic code converts these into a standard * &struct net_device_stats. * @stats_buffer: DMA buffer for statistics - * @stats_lock: Statistics update lock + * @stats_lock: Statistics update lock. Serialises statistics fetches + * @stats_enabled: Temporarily disable statistics fetches. + * Serialised by @stats_lock * @mac_address: Permanent MAC address * @phy_type: PHY type * @phy_lock: PHY access lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) * @mii: PHY interface - * @phy_mode: PHY operating mode + * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @link_up: Link status * @link_options: Link options (MII/GMII format) * @n_link_state_changes: Number of times the link has changed state @@ -733,6 +737,7 @@ struct efx_nic { struct mutex mac_lock; bool port_enabled; + bool port_inhibited; bool port_initialized; struct net_device *net_dev; @@ -744,6 +749,7 @@ struct efx_nic { struct efx_mac_stats mac_stats; struct efx_buffer stats_buffer; spinlock_t stats_lock; + bool stats_enabled; unsigned char mac_address[ETH_ALEN]; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 2f7def65767..362956e3fe1 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -27,6 +27,9 @@ #include "boards.h" #include "workarounds.h" #include "mac.h" +#include "spi.h" +#include "falcon_io.h" +#include "mdio_10g.h" /* * Loopback test packet structure @@ -51,7 +54,7 @@ static const char *payload_msg = "Hello world! This is an Efx loopback test in progress!"; /** - * efx_selftest_state - persistent state during a selftest + * efx_loopback_state - persistent state during a loopback selftest * @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 @@ -59,7 +62,7 @@ static const char *payload_msg = * @rx_bad: RX bad packet count * @payload: Payload used in tests */ -struct efx_selftest_state { +struct efx_loopback_state { bool flush; int packet_count; struct sk_buff **skbs; @@ -74,21 +77,65 @@ struct efx_selftest_state { /************************************************************************** * - * Configurable values + * MII, NVRAM and register tests * **************************************************************************/ -/* Level of loopback testing - * - * The maximum packet burst length is 16**(n-1), i.e. - * - * - Level 0 : no packets - * - Level 1 : 1 packet - * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets) - * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets) - * - */ -static unsigned int loopback_test_level = 3; +static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc = 0; + u16 physid1, physid2; + struct mii_if_info *mii = &efx->mii; + struct net_device *net_dev = efx->net_dev; + + if (efx->phy_type == PHY_TYPE_NONE) + return 0; + + mutex_lock(&efx->mac_lock); + tests->mii = -1; + + physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); + physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); + + if ((physid1 == 0x0000) || (physid1 == 0xffff) || + (physid2 == 0x0000) || (physid2 == 0xffff)) { + EFX_ERR(efx, "no MII PHY present with ID %d\n", + mii->phy_id); + rc = -EINVAL; + goto out; + } + + rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + if (rc) + goto out; + +out: + mutex_unlock(&efx->mac_lock); + tests->mii = rc ? -1 : 1; + return rc; +} + +static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc; + + rc = falcon_read_nvram(efx, NULL); + tests->nvram = rc ? -1 : 1; + return rc; +} + +static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) +{ + int rc; + + /* Not supported on A-series silicon */ + if (falcon_rev(efx) < FALCON_REV_B0) + return 0; + + rc = falcon_test_registers(efx); + tests->registers = rc ? -1 : 1; + return rc; +} /************************************************************************** * @@ -199,39 +246,18 @@ static int efx_test_eventq_irq(struct efx_channel *channel, return 0; } -/************************************************************************** - * - * PHY testing - * - **************************************************************************/ - -/* Check PHY presence by reading the PHY ID registers */ -static int efx_test_phy(struct efx_nic *efx, - struct efx_self_tests *tests) +static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) { - u16 physid1, physid2; - struct mii_if_info *mii = &efx->mii; - struct net_device *net_dev = efx->net_dev; - - if (efx->phy_type == PHY_TYPE_NONE) - return 0; - - EFX_LOG(efx, "testing PHY presence\n"); - tests->phy_ok = -1; - - physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); - physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); + int rc; - if ((physid1 != 0x0000) && (physid1 != 0xffff) && - (physid2 != 0x0000) && (physid2 != 0xffff)) { - EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n", - mii->phy_id, physid1, physid2); - tests->phy_ok = 1; + if (!efx->phy_op->test) return 0; - } - EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id); - return -ENODEV; + mutex_lock(&efx->mac_lock); + rc = efx->phy_op->test(efx); + mutex_unlock(&efx->mac_lock); + tests->phy = rc ? -1 : 1; + return rc; } /************************************************************************** @@ -247,7 +273,7 @@ static int efx_test_phy(struct efx_nic *efx, void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len) { - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *received; struct efx_loopback_payload *payload; @@ -258,7 +284,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, return; payload = &state->payload; - + received = (struct efx_loopback_payload *) buf_ptr; received->ip.saddr = payload->ip.saddr; if (state->offload_csum) @@ -332,7 +358,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, /* Initialise an efx_selftest_state for a new iteration */ static void efx_iterate_state(struct efx_nic *efx) { - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct net_device *net_dev = efx->net_dev; struct efx_loopback_payload *payload = &state->payload; @@ -368,14 +394,14 @@ static void efx_iterate_state(struct efx_nic *efx) static int efx_begin_loopback(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *payload; struct sk_buff *skb; int i, rc; /* Transmit N copies of buffer */ for (i = 0; i < state->packet_count; i++) { - /* Allocate an skb, holding an extra reference for + /* Allocate an skb, holding an extra reference for * transmit completion counting */ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); if (!skb) @@ -416,7 +442,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) static int efx_poll_loopback(struct efx_nic *efx) { - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct efx_channel *channel; /* NAPI polling is not enabled, so process channels @@ -432,7 +458,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, struct efx_loopback_self_tests *lb_tests) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; struct sk_buff *skb; int tx_done = 0, rx_good, rx_bad; int i, rc = 0; @@ -491,10 +517,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, struct efx_loopback_self_tests *lb_tests) { struct efx_nic *efx = tx_queue->efx; - struct efx_selftest_state *state = efx->loopback_selftest; + struct efx_loopback_state *state = efx->loopback_selftest; int i, begin_rc, end_rc; - for (i = 0; i < loopback_test_level; i++) { + for (i = 0; i < 3; i++) { /* Determine how many packets to send */ state->packet_count = (efx->type->txd_ring_mask + 1) / 3; state->packet_count = min(1 << (i << 2), state->packet_count); @@ -537,42 +563,28 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } -static int efx_test_loopbacks(struct efx_nic *efx, +static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, struct efx_self_tests *tests, unsigned int loopback_modes) { - struct efx_selftest_state *state = efx->loopback_selftest; - struct ethtool_cmd ecmd, ecmd_loopback; + enum efx_loopback_mode mode; + struct efx_loopback_state *state; struct efx_tx_queue *tx_queue; - enum efx_loopback_mode old_mode, mode; bool link_up; - int count, rc; - - rc = efx_ethtool_get_settings(efx->net_dev, &ecmd); - if (rc) { - EFX_ERR(efx, "could not get GMII settings\n"); - return rc; - } - old_mode = efx->loopback_mode; - - /* Disable autonegotiation for the purposes of loopback */ - memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback)); - if (ecmd_loopback.autoneg == AUTONEG_ENABLE) { - ecmd_loopback.autoneg = AUTONEG_DISABLE; - ecmd_loopback.duplex = DUPLEX_FULL; - ecmd_loopback.speed = SPEED_10000; - } + int count, rc = 0; - rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback); - if (rc) { - EFX_ERR(efx, "could not disable autonegotiation\n"); - goto out; - } - tests->loopback_speed = ecmd_loopback.speed; - tests->loopback_full_duplex = ecmd_loopback.duplex; + /* Set the port loopback_selftest member. From this point on + * all received packets will be dropped. Mark the state as + * "flushing" so all inflight packets are dropped */ + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + BUG_ON(efx->loopback_selftest); + state->flush = true; + efx->loopback_selftest = state; /* Test all supported loopback modes */ - for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { + for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(loopback_modes & (1 << mode))) continue; @@ -601,7 +613,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, */ link_up = efx->link_up; if (!falcon_xaui_link_ok(efx)) - link_up = 0; + link_up = false; } while ((++count < 20) && !link_up); @@ -629,10 +641,11 @@ static int efx_test_loopbacks(struct efx_nic *efx, } out: - /* Take out of loopback and restore PHY settings */ + /* Remove the flush. The caller will remove the loopback setting */ state->flush = true; - efx->loopback_mode = old_mode; - efx_ethtool_set_settings(efx->net_dev, &ecmd); + efx->loopback_selftest = NULL; + wmb(); + kfree(state); return rc; } @@ -648,18 +661,27 @@ static int efx_test_loopbacks(struct efx_nic *efx, int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) { struct efx_channel *channel; - int rc; + int rc, rc2 = 0; + + rc = efx_test_mii(efx, tests); + if (rc && !rc2) + rc2 = rc; + + rc = efx_test_nvram(efx, tests); + if (rc && !rc2) + rc2 = rc; rc = efx_test_interrupts(efx, tests); - if (rc) - return rc; + if (rc && !rc2) + rc2 = rc; + efx_for_each_channel(channel, efx) { rc = efx_test_eventq_irq(channel, tests); - if (rc) - return rc; + if (rc && !rc2) + rc2 = rc; } - rc = efx_test_phy(efx, tests); - return rc; + + return rc2; } /* Offline (i.e. disruptive) testing @@ -667,27 +689,66 @@ int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) int efx_offline_test(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { - struct efx_selftest_state *state; - int rc; + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + struct ethtool_cmd ecmd, ecmd_test; + int rc, rc2 = 0; + + /* force the carrier state off so the kernel doesn't transmit during + * the loopback test, and the watchdog timeout doesn't fire. Also put + * falcon into loopback for the register test. + */ + mutex_lock(&efx->mac_lock); + efx->port_inhibited = true; + if (efx->loopback_modes) + efx->loopback_mode = __ffs(efx->loopback_modes); + __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); + + /* free up all consumers of SRAM (including all the queues) */ + efx_reset_down(efx, &ecmd); + + rc = efx_test_chip(efx, tests); + if (rc && !rc2) + rc2 = rc; + + /* reset the chip to recover from the register test */ + rc = falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Modify the saved ecmd so that when efx_reset_up() restores the phy + * state, AN is disabled, and the phy is powered, and out of loopback */ + memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); + if (ecmd_test.autoneg == AUTONEG_ENABLE) { + ecmd_test.autoneg = AUTONEG_DISABLE; + ecmd_test.duplex = DUPLEX_FULL; + ecmd_test.speed = SPEED_10000; + } + efx->loopback_mode = LOOPBACK_NONE; - /* Create a selftest_state structure to hold state for the test */ - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; + rc = efx_reset_up(efx, &ecmd_test, rc == 0); + if (rc) { + EFX_ERR(efx, "Unable to recover from chip test\n"); + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + return rc; + } - /* Set the port loopback_selftest member. From this point on - * all received packets will be dropped. Mark the state as - * "flushing" so all inflight packets are dropped */ - BUG_ON(efx->loopback_selftest); - state->flush = true; - efx->loopback_selftest = state; + tests->loopback_speed = ecmd_test.speed; + tests->loopback_full_duplex = ecmd_test.duplex; - rc = efx_test_loopbacks(efx, tests, loopback_modes); + rc = efx_test_phy(efx, tests); + if (rc && !rc2) + rc2 = rc; - efx->loopback_selftest = NULL; - wmb(); - kfree(state); + rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); + if (rc && !rc2) + rc2 = rc; - return rc; + /* restore the PHY to the previous state */ + efx->loopback_mode = loopback_mode; + efx->phy_mode = phy_mode; + efx->port_inhibited = false; + efx_ethtool_set_settings(efx->net_dev, &ecmd); + + return rc2; } diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index cd59f00e282..fc15df15d76 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -29,14 +29,19 @@ struct efx_loopback_self_tests { * indicates failure. */ struct efx_self_tests { + /* online tests */ + int mii; + int nvram; int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; int eventq_int[EFX_MAX_CHANNELS]; int eventq_poll[EFX_MAX_CHANNELS]; - int phy_ok; + /* offline tests */ + int registers; + int phy; int loopback_speed; int loopback_full_duplex; - struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX]; + struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; extern void efx_loopback_rx_packet(struct efx_nic *efx, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 499e127f6dd..8412dbe1e8f 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -65,25 +65,10 @@ #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) -/* Self test (BIST) control register */ -#define PMA_PMD_BIST_CTRL_REG (0xc014) -#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */ -#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */ -#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */ -/* Self test status register */ -#define PMA_PMD_BIST_STAT_REG (0xc015) -#define PMA_PMD_BIST_ENX_LBN (3) -#define PMA_PMD_BIST_PMA_LBN (2) -#define PMA_PMD_BIST_RXD_LBN (1) -#define PMA_PMD_BIST_AFE_LBN (0) - /* Special Software reset register */ #define PMA_PMD_EXT_CTRL_REG 49152 #define PMA_PMD_EXT_SSR_LBN 15 -#define BIST_MAX_DELAY (1000) -#define BIST_POLL_DELAY (10) - /* Misc register defines */ #define PCS_CLOCK_CTRL_REG 0xd801 #define PLL312_RST_N_LBN 2 @@ -491,6 +476,12 @@ static void tenxpress_reset_xaui(struct efx_nic *efx) udelay(10); } +static int tenxpress_phy_test(struct efx_nic *efx) +{ + /* BIST is automatically run after a special software reset */ + return tenxpress_special_reset(efx); +} + struct efx_phy_operations falcon_tenxpress_phy_ops = { .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, @@ -498,6 +489,7 @@ struct efx_phy_operations falcon_tenxpress_phy_ops = { .fini = tenxpress_phy_fini, .clear_interrupt = tenxpress_phy_clear_interrupt, .reset_xaui = tenxpress_reset_xaui, + .test = tenxpress_phy_test, .mmds = TENXPRESS_REQUIRED_DEVS, .loopbacks = TENXPRESS_LOOPBACKS, }; -- cgit v1.2.3-70-g09d2 From 6bc5d3a9334401d788e1adf8b71add211265bc8b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 1 Sep 2008 12:49:37 +0100 Subject: sfc: Make queue flushes more reliable Increase the potential retry count for RX flushes from 5 to 100. Stop polling the RX_DESC_PTR_TBL to infer that a flush might have happened. Instead absolutely rely on the flush events, unless bug 7803 applies (Falcon rev A only). To keep things quick, request flushes for every TX and RX queue up front, and match up the events to requests. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/efx.c | 15 ++- drivers/net/sfc/falcon.c | 247 ++++++++++++++++++++++--------------------- drivers/net/sfc/falcon.h | 1 + drivers/net/sfc/net_driver.h | 4 + 4 files changed, 141 insertions(+), 126 deletions(-) (limited to 'drivers/net/sfc/falcon.h') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f65e313c2be..06ea71c7e34 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -445,10 +445,17 @@ static void efx_fini_channels(struct efx_nic *efx) struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + int rc; EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); + rc = falcon_flush_queues(efx); + if (rc) + EFX_ERR(efx, "failed to flush queues\n"); + else + EFX_LOG(efx, "successfully flushed all queues\n"); + efx_for_each_channel(channel, efx) { EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel); @@ -456,13 +463,6 @@ static void efx_fini_channels(struct efx_nic *efx) efx_fini_rx_queue(rx_queue); efx_for_each_channel_tx_queue(tx_queue, channel) efx_fini_tx_queue(tx_queue); - } - - /* Do the event queues last so that we can handle flush events - * for all DMA queues. */ - efx_for_each_channel(channel, efx) { - EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel); - efx_fini_eventq(channel); } } @@ -1092,7 +1092,6 @@ static void efx_stop_all(struct efx_nic *efx) /* Isolate the MAC from the TX and RX engines, so that queue * flushes will complete in a timely fashion. */ - falcon_deconfigure_mac_wrapper(efx); falcon_drain_tx_fifo(efx); /* Stop the kernel transmit interface late, so the watchdog diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index ad192f82c5e..70c681ecdab 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -108,10 +108,10 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); /* Max number of internal errors. After this resets will not be performed */ #define FALCON_MAX_INT_ERRORS 4 -/* Maximum period that we wait for flush events. If the flush event - * doesn't arrive in this period of time then we check if the queue - * was disabled anyway. */ -#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */ +/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times + */ +#define FALCON_FLUSH_INTERVAL 10 +#define FALCON_FLUSH_POLL_COUNT 100 /************************************************************************** * @@ -452,6 +452,8 @@ 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; + /* Pin TX descriptor ring */ falcon_init_special_buffer(efx, &tx_queue->txd); @@ -492,60 +494,16 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue) } } -static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) +static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - struct efx_channel *channel = &efx->channel[0]; efx_oword_t tx_flush_descq; - unsigned int read_ptr, i; /* Post a flush command */ EFX_POPULATE_OWORD_2(tx_flush_descq, TX_FLUSH_DESCQ_CMD, 1, TX_FLUSH_DESCQ, tx_queue->queue); falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER); - msleep(FALCON_FLUSH_TIMEOUT); - - if (EFX_WORKAROUND_7803(efx)) - return 0; - - /* Look for a flush completed event */ - read_ptr = channel->eventq_read_ptr; - for (i = 0; i < FALCON_EVQ_SIZE; ++i) { - efx_qword_t *event = falcon_event(channel, read_ptr); - int ev_code, ev_sub_code, ev_queue; - if (!falcon_event_present(event)) - break; - - ev_code = EFX_QWORD_FIELD(*event, EV_CODE); - ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); - ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID); - if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) && - (ev_queue == tx_queue->queue)) { - EFX_LOG(efx, "tx queue %d flush command succesful\n", - tx_queue->queue); - return 0; - } - - read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } - - if (EFX_WORKAROUND_11557(efx)) { - efx_oword_t reg; - bool enabled; - - falcon_read_table(efx, ®, efx->type->txd_ptr_tbl_base, - tx_queue->queue); - enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN); - if (!enabled) { - EFX_LOG(efx, "tx queue %d disabled without a " - "flush event seen\n", tx_queue->queue); - return 0; - } - } - - EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue); - return -ETIMEDOUT; } void falcon_fini_tx(struct efx_tx_queue *tx_queue) @@ -553,9 +511,8 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue) struct efx_nic *efx = tx_queue->efx; efx_oword_t tx_desc_ptr; - /* Stop the hardware using the queue */ - if (falcon_flush_tx_queue(tx_queue)) - EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue); + /* The queue should have been flushed */ + WARN_ON(!tx_queue->flushed); /* Remove TX descriptor ring from card */ EFX_ZERO_OWORD(tx_desc_ptr); @@ -643,6 +600,8 @@ 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; + /* Pin RX descriptor ring */ falcon_init_special_buffer(efx, &rx_queue->rxd); @@ -663,11 +622,9 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue) rx_queue->queue); } -static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) +static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - struct efx_channel *channel = &efx->channel[0]; - unsigned int read_ptr, i; efx_oword_t rx_flush_descq; /* Post a flush command */ @@ -675,76 +632,15 @@ static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) RX_FLUSH_DESCQ_CMD, 1, RX_FLUSH_DESCQ, rx_queue->queue); falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER); - msleep(FALCON_FLUSH_TIMEOUT); - - if (EFX_WORKAROUND_7803(efx)) - return 0; - - /* Look for a flush completed event */ - read_ptr = channel->eventq_read_ptr; - for (i = 0; i < FALCON_EVQ_SIZE; ++i) { - efx_qword_t *event = falcon_event(channel, read_ptr); - int ev_code, ev_sub_code, ev_queue; - bool ev_failed; - if (!falcon_event_present(event)) - break; - - ev_code = EFX_QWORD_FIELD(*event, EV_CODE); - ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); - ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID); - ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL); - - if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) && - (ev_queue == rx_queue->queue)) { - if (ev_failed) { - EFX_INFO(efx, "rx queue %d flush command " - "failed\n", rx_queue->queue); - return -EAGAIN; - } else { - EFX_LOG(efx, "rx queue %d flush command " - "succesful\n", rx_queue->queue); - return 0; - } - } - - read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; - } - - if (EFX_WORKAROUND_11557(efx)) { - efx_oword_t reg; - bool enabled; - - falcon_read_table(efx, ®, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); - enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN); - if (!enabled) { - EFX_LOG(efx, "rx queue %d disabled without a " - "flush event seen\n", rx_queue->queue); - return 0; - } - } - - EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue); - return -ETIMEDOUT; } void falcon_fini_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; - int i, rc; - /* Try and flush the rx queue. This may need to be repeated */ - for (i = 0; i < 5; i++) { - rc = falcon_flush_rx_queue(rx_queue); - if (rc == -EAGAIN) - continue; - break; - } - if (rc) { - EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue); - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } + /* The queue should already have been flushed */ + WARN_ON(!rx_queue->flushed); /* Remove RX descriptor ring from card */ EFX_ZERO_OWORD(rx_desc_ptr); @@ -1255,6 +1151,121 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) falcon_generate_event(channel, &test_event); } +/************************************************************************** + * + * Flush handling + * + **************************************************************************/ + + +static void falcon_poll_flush_events(struct efx_nic *efx) +{ + struct efx_channel *channel = &efx->channel[0]; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + unsigned int read_ptr, i; + + read_ptr = channel->eventq_read_ptr; + for (i = 0; i < FALCON_EVQ_SIZE; ++i) { + efx_qword_t *event = falcon_event(channel, read_ptr); + int ev_code, ev_sub_code, ev_queue; + bool ev_failed; + if (!falcon_event_present(event)) + break; + + ev_code = EFX_QWORD_FIELD(*event, EV_CODE); + if (ev_code != DRIVER_EV_DECODE) + continue; + + ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); + switch (ev_sub_code) { + case TX_DESCQ_FLS_DONE_EV_DECODE: + ev_queue = EFX_QWORD_FIELD(*event, + DRIVER_EV_TX_DESCQ_ID); + if (ev_queue < EFX_TX_QUEUE_COUNT) { + tx_queue = efx->tx_queue + ev_queue; + tx_queue->flushed = true; + } + break; + case RX_DESCQ_FLS_DONE_EV_DECODE: + ev_queue = EFX_QWORD_FIELD(*event, + DRIVER_EV_RX_DESCQ_ID); + ev_failed = EFX_QWORD_FIELD(*event, + 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; + } + break; + } + + read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; + } +} + +/* Handle tx and rx flushes at the same time, since they run in + * parallel in the hardware and there's no reason for us to + * serialise them */ +int falcon_flush_queues(struct efx_nic *efx) +{ + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int i; + bool outstanding; + + /* Issue flush requests */ + efx_for_each_tx_queue(tx_queue, efx) { + tx_queue->flushed = false; + 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 */ + for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) { + msleep(FALCON_FLUSH_INTERVAL); + falcon_poll_flush_events(efx); + + /* 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) + return 0; + } + + /* 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. */ + efx_for_each_tx_queue(tx_queue, efx) { + if (!tx_queue->flushed) + EFX_ERR(efx, "tx queue %d flush command timed out\n", + tx_queue->queue); + tx_queue->flushed = true; + } + efx_for_each_rx_queue(rx_queue, efx) { + if (!rx_queue->flushed) + EFX_ERR(efx, "rx queue %d flush command timed out\n", + rx_queue->queue); + rx_queue->flushed = true; + } + + if (EFX_WORKAROUND_7803(efx)) + return 0; + + return -ETIMEDOUT; +} /************************************************************************** * diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 30d61e48ac6..be025ba7a6c 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -86,6 +86,7 @@ extern void falcon_fini_interrupt(struct efx_nic *efx); extern int falcon_probe_nic(struct efx_nic *efx); extern int falcon_probe_resources(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_remove_resources(struct efx_nic *efx); extern void falcon_remove_nic(struct efx_nic *efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index be3d2ba3b74..868ad1e703f 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -160,6 +160,7 @@ struct efx_tx_buffer { * @channel: The associated channel * @buffer: The software buffer ring * @txd: The hardware descriptor ring + * @flushed: Used when handling queue flushing * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. * @stopped: Stopped count. @@ -192,6 +193,7 @@ struct efx_tx_queue { struct efx_nic *nic; struct efx_tx_buffer *buffer; struct efx_special_buffer txd; + bool flushed; /* Members used mainly on the completion path */ unsigned int read_count ____cacheline_aligned_in_smp; @@ -260,6 +262,7 @@ struct efx_rx_buffer { * the remaining space in the allocation. * @buf_dma_addr: Page's DMA address. * @buf_data: Page's host address. + * @flushed: Use when handling queue flushing */ struct efx_rx_queue { struct efx_nic *efx; @@ -285,6 +288,7 @@ struct efx_rx_queue { struct page *buf_page; dma_addr_t buf_dma_addr; char *buf_data; + bool flushed; }; /** -- cgit v1.2.3-70-g09d2