From 3ffeabdd2bc62e0ebcb1a51a5d959a86a7a915fc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:30:58 +0000 Subject: sfc: Eliminate indirect lookups of queue size constants Move size and mask definitions into efx.h; calculate page orders in falcon.c. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index cc4b2f99989..8b67553046e 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -290,7 +290,7 @@ void efx_process_channel_now(struct efx_channel *channel) napi_disable(&channel->napi_str); /* Poll the channel */ - efx_process_channel(channel, efx->type->evq_size); + efx_process_channel(channel, EFX_EVQ_SIZE); /* Ack the eventq. This may cause an interrupt to be generated * when they are reenabled */ @@ -1981,17 +1981,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->type = type; - /* Sanity-check NIC type */ - EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask & - (efx->type->txd_ring_mask + 1)); - EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask & - (efx->type->rxd_ring_mask + 1)); - EFX_BUG_ON_PARANOID(efx->type->evq_size & - (efx->type->evq_size - 1)); /* As close as we can get to guaranteeing that we don't overflow */ - EFX_BUG_ON_PARANOID(efx->type->evq_size < - (efx->type->txd_ring_mask + 1 + - efx->type->rxd_ring_mask + 1)); + BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE); + EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); /* Higher numbered interrupt modes are less capable! */ -- cgit v1.2.3-70-g09d2 From f01865f0649f3d42b70fec8968adfd53734a3380 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:31:37 +0000 Subject: sfc: Change order of device removal to reverse of probe order This makes efx_pci_remove_main() more obviously the inverse of efx_pci_probe_main(), and matches our out-of-tree driver. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 8b67553046e..862e4832f61 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2025,12 +2025,12 @@ static void efx_pci_remove_main(struct efx_nic *efx) if (!efx->membase) return; + falcon_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); /* Shutdown the board, then the NIC and board state */ efx->board_info.fini(efx); - falcon_fini_interrupt(efx); efx_fini_napi(efx); efx_remove_all(efx); -- cgit v1.2.3-70-g09d2 From 0d86ebd815416efb4e95ca70c3b8e65b476c5f9f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:32:13 +0000 Subject: sfc: Maintain interrupt moderation values in ticks, not microseconds This simplifies the implementation a lot. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 41 +++++++++++++++++++++++------------------ drivers/net/sfc/ethtool.c | 8 +++----- drivers/net/sfc/falcon.c | 11 +---------- drivers/net/sfc/net_driver.h | 2 +- 4 files changed, 28 insertions(+), 34 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 862e4832f61..30951fb3d20 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -228,26 +228,20 @@ static int efx_poll(struct napi_struct *napi, int budget) if (channel->used_flags & EFX_USED_BY_RX && efx->irq_rx_adaptive && unlikely(++channel->irq_count == 1000)) { - unsigned old_irq_moderation = channel->irq_moderation; - if (unlikely(channel->irq_mod_score < irq_adapt_low_thresh)) { - channel->irq_moderation = - max_t(int, - channel->irq_moderation - - FALCON_IRQ_MOD_RESOLUTION, - FALCON_IRQ_MOD_RESOLUTION); + if (channel->irq_moderation > 1) { + channel->irq_moderation -= 1; + falcon_set_int_moderation(channel); + } } else if (unlikely(channel->irq_mod_score > irq_adapt_high_thresh)) { - channel->irq_moderation = - min(channel->irq_moderation + - FALCON_IRQ_MOD_RESOLUTION, - efx->irq_rx_moderation); + if (channel->irq_moderation < + efx->irq_rx_moderation) { + channel->irq_moderation += 1; + falcon_set_int_moderation(channel); + } } - - if (channel->irq_moderation != old_irq_moderation) - falcon_set_int_moderation(channel); - channel->irq_count = 0; channel->irq_mod_score = 0; } @@ -1220,22 +1214,33 @@ void efx_flush_queues(struct efx_nic *efx) * **************************************************************************/ +static unsigned irq_mod_ticks(int usecs, int resolution) +{ + if (usecs <= 0) + return 0; /* cannot receive interrupts ahead of time :-) */ + if (usecs < resolution) + return 1; /* never round down to 0 */ + return usecs / resolution; +} + /* Set interrupt moderation parameters */ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, bool rx_adaptive) { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION); + unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION); EFX_ASSERT_RESET_SERIALISED(efx); efx_for_each_tx_queue(tx_queue, efx) - tx_queue->channel->irq_moderation = tx_usecs; + tx_queue->channel->irq_moderation = tx_ticks; efx->irq_rx_adaptive = rx_adaptive; - efx->irq_rx_moderation = rx_usecs; + efx->irq_rx_moderation = rx_ticks; efx_for_each_rx_queue(rx_queue, efx) - rx_queue->channel->irq_moderation = rx_usecs; + rx_queue->channel->irq_moderation = rx_ticks; } /************************************************************************** diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 45018f283ff..a313b61c8ff 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -618,6 +618,9 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation; + coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; + coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; + return 0; } @@ -656,11 +659,6 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, } efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); - - /* Reset channel to pick up new moderation value. Note that - * this may change the value of the irq_moderation field - * (e.g. to allow for hardware timer granularity). - */ efx_for_each_channel(channel, efx) falcon_set_int_moderation(channel); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 1582df7aba7..e3c33fa06c8 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1063,20 +1063,11 @@ void falcon_set_int_moderation(struct efx_channel *channel) /* Set timer register */ if (channel->irq_moderation) { - /* Round to resolution supported by hardware. The value we - * program is based at 0. So actual interrupt moderation - * achieved is ((x + 1) * res). - */ - channel->irq_moderation -= (channel->irq_moderation % - FALCON_IRQ_MOD_RESOLUTION); - if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION) - channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION; EFX_POPULATE_DWORD_2(timer_cmd, FRF_AB_TC_TIMER_MODE, FFE_BB_TIMER_MODE_INT_HLDOFF, FRF_AB_TC_TIMER_VAL, - channel->irq_moderation / - FALCON_IRQ_MOD_RESOLUTION - 1); + channel->irq_moderation - 1); } else { EFX_POPULATE_DWORD_2(timer_cmd, FRF_AB_TC_TIMER_MODE, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 25b793327c1..c8b6998d7fc 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -327,7 +327,7 @@ enum efx_rx_alloc_method { * @used_flags: Channel is used by net driver * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) - * @irq_moderation: IRQ moderation value (in us) + * @irq_moderation: IRQ moderation value (in hardware ticks) * @napi_dev: Net device used with NAPI * @napi_str: NAPI control structure * @reset_work: Scheduled reset work thread -- cgit v1.2.3-70-g09d2 From dc803df8dd68a045bea4753f5300eeecb961ca2d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:32:33 +0000 Subject: sfc: Remove pointless abstraction of memory BAR number Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 16 +++++++--------- drivers/net/sfc/efx.h | 3 +++ drivers/net/sfc/falcon.c | 2 -- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 30951fb3d20..29003fe9cb4 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -818,9 +818,8 @@ static int efx_init_io(struct efx_nic *efx) goto fail2; } - efx->membase_phys = pci_resource_start(efx->pci_dev, - efx->type->mem_bar); - rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc"); + efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); + rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); if (rc) { EFX_ERR(efx, "request for memory BAR failed\n"); rc = -EIO; @@ -829,21 +828,20 @@ static int efx_init_io(struct efx_nic *efx) efx->membase = ioremap_nocache(efx->membase_phys, efx->type->mem_map_size); if (!efx->membase) { - EFX_ERR(efx, "could not map memory BAR %d at %llx+%x\n", - efx->type->mem_bar, + EFX_ERR(efx, "could not map memory BAR at %llx+%x\n", (unsigned long long)efx->membase_phys, efx->type->mem_map_size); rc = -ENOMEM; goto fail4; } - EFX_LOG(efx, "memory BAR %u at %llx+%x (virtual %p)\n", - efx->type->mem_bar, (unsigned long long)efx->membase_phys, + EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n", + (unsigned long long)efx->membase_phys, efx->type->mem_map_size, efx->membase); return 0; fail4: - pci_release_region(efx->pci_dev, efx->type->mem_bar); + pci_release_region(efx->pci_dev, EFX_MEM_BAR); fail3: efx->membase_phys = 0; fail2: @@ -862,7 +860,7 @@ static void efx_fini_io(struct efx_nic *efx) } if (efx->membase_phys) { - pci_release_region(efx->pci_dev, efx->type->mem_bar); + pci_release_region(efx->pci_dev, EFX_MEM_BAR); efx->membase_phys = 0; } diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index ae76760d4f4..179e0e3b0ec 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -19,6 +19,9 @@ #define FALCON_A_S_DEVID 0x6703 #define FALCON_B_P_DEVID 0x0710 +/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ +#define EFX_MEM_BAR 2 + /* TX */ extern netdev_tx_t efx_xmit(struct efx_nic *efx, struct efx_tx_queue *tx_queue, diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index e3c33fa06c8..ade27920a96 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -3117,7 +3117,6 @@ void falcon_update_nic_stats(struct efx_nic *efx) */ struct efx_nic_type falcon_a_nic_type = { - .mem_bar = 2, .mem_map_size = 0x20000, .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, @@ -3131,7 +3130,6 @@ struct efx_nic_type falcon_a_nic_type = { }; struct efx_nic_type falcon_b_nic_type = { - .mem_bar = 2, /* Map everything up to and including the RSS indirection * table. Don't map MSI-X table, MSI-X PBA since Linux * requires that they not be mapped. */ -- cgit v1.2.3-70-g09d2 From be4b163b28917499ea1f8755eee8509ee2675ec3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:32:51 +0000 Subject: sfc: Remove incorrect assertion from efx_pci_remove_main() Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 29003fe9cb4..c9258017632 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2022,8 +2022,6 @@ static void efx_fini_struct(struct efx_nic *efx) */ static void efx_pci_remove_main(struct efx_nic *efx) { - EFX_ASSERT_RESET_SERIALISED(efx); - /* Skip everything if we never obtained a valid membase */ if (!efx->membase) return; -- cgit v1.2.3-70-g09d2 From 2ed380a59b3725dc5fbda3627792172afbefc8eb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:33:00 +0000 Subject: sfc: Remove unnecessary tests of efx->membase These cleanup functions will never be called if the MMIO region could not be mapped. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index c9258017632..8fc6a6edc36 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2022,10 +2022,6 @@ static void efx_fini_struct(struct efx_nic *efx) */ static void efx_pci_remove_main(struct efx_nic *efx) { - /* Skip everything if we never obtained a valid membase */ - if (!efx->membase) - return; - falcon_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); @@ -2056,9 +2052,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) /* Allow any queued efx_resets() to complete */ rtnl_unlock(); - if (efx->membase == NULL) - goto out; - efx_unregister_netdev(efx); efx_mtd_remove(efx); @@ -2071,7 +2064,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_pci_remove_main(efx); -out: efx_fini_io(efx); EFX_LOG(efx, "shutdown successful\n"); -- cgit v1.2.3-70-g09d2 From a5211bb5f72c55d936dab56363ca9755981164bd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 23 Oct 2009 08:33:09 +0000 Subject: sfc: Move MTD probe after netdev registration and name allocation The MTD partition is named based on the netdev name, which is set to 'eth%d' before registration. Also, the MTD partition will currently be left registered if netdev registration fails. Fix both these problems by moving the MTD probe after netdev registration. Hold the RTNL to serialise this with the netdev notifier that calls efx_mtd_rename(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 8fc6a6edc36..0d0243b7ac3 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2209,13 +2209,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, * MAC stats succeeds. */ efx->state = STATE_RUNNING; - efx_mtd_probe(efx); /* allowed to fail */ - rc = efx_register_netdev(efx); if (rc) goto fail5; EFX_LOG(efx, "initialisation successful\n"); + + rtnl_lock(); + efx_mtd_probe(efx); /* allowed to fail */ + rtnl_unlock(); return 0; fail5: -- cgit v1.2.3-70-g09d2 From 398468ed1b5c61fe8bcbc8cc1ed323e3c23b58ef Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:03:45 +0000 Subject: sfc: Use a single blink implementation Only some PHYs have firmware support for a LED blink mode, so we currently blink the others in a timer function. Since all PHYs have simple on and off modes, we don't gain anything by using multiple blink implementations. Also, since we have a process context there is no need to use a timer. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 7 +++-- drivers/net/sfc/efx.h | 3 +- drivers/net/sfc/ethtool.c | 16 +++++----- drivers/net/sfc/falcon_boards.c | 66 ++++++++++++++--------------------------- drivers/net/sfc/net_driver.h | 18 +++++------ drivers/net/sfc/phy.h | 2 +- drivers/net/sfc/qt202x_phy.c | 3 -- drivers/net/sfc/tenxpress.c | 24 ++++++++++----- 8 files changed, 62 insertions(+), 77 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 0d0243b7ac3..612cd815088 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1890,7 +1890,9 @@ int efx_port_dummy_op_int(struct efx_nic *efx) return 0; } void efx_port_dummy_op_void(struct efx_nic *efx) {} -void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} +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, @@ -1909,9 +1911,8 @@ static struct efx_phy_operations efx_dummy_phy_operations = { static struct efx_board efx_dummy_board_info = { .init = efx_port_dummy_op_int, .init_leds = efx_port_dummy_op_void, - .set_id_led = efx_port_dummy_op_blink, + .set_id_led = efx_port_dummy_op_set_id_led, .monitor = efx_port_dummy_op_int, - .blink = efx_port_dummy_op_blink, .fini = efx_port_dummy_op_void, }; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 179e0e3b0ec..6f463946516 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -69,7 +69,8 @@ extern void efx_hex_dump(const u8 *, unsigned int, const char *); /* Dummy PHY ops for PHY drivers */ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); -extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); +extern void +efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /* MTD */ #ifdef CONFIG_SFC_MTD diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index a313b61c8ff..18e02712818 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -187,13 +187,15 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) { struct efx_nic *efx = netdev_priv(net_dev); - efx->board_info.blink(efx, 1); - set_current_state(TASK_INTERRUPTIBLE); - if (count) - schedule_timeout(count * HZ); - else - schedule(); - efx->board_info.blink(efx, 0); + do { + efx->board_info.set_id_led(efx, EFX_LED_ON); + schedule_timeout_interruptible(HZ / 2); + + efx->board_info.set_id_led(efx, EFX_LED_OFF); + schedule_timeout_interruptible(HZ / 2); + } while (!signal_pending(current) && --count != 0); + + efx->board_info.set_id_led(efx, EFX_LED_DEFAULT); return 0; } diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index d31c134981f..b2505fc5c1f 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -29,40 +29,6 @@ #define FALCON_BOARD_SFN4111T 0x51 #define FALCON_BOARD_SFN4112F 0x52 -/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */ -#define BLINK_INTERVAL (HZ/2) - -static void blink_led_timer(unsigned long context) -{ - struct efx_nic *efx = (struct efx_nic *)context; - struct efx_board *board = &efx->board_info; - - board->set_id_led(efx, board->blink_state); - board->blink_state = !board->blink_state; - if (board->blink_resubmit) - mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL); -} - -static void board_blink(struct efx_nic *efx, bool blink) -{ - struct efx_board *board = &efx->board_info; - - /* The rtnl mutex serialises all ethtool ioctls, so - * nothing special needs doing here. */ - if (blink) { - board->blink_resubmit = true; - board->blink_state = false; - setup_timer(&board->blink_timer, blink_led_timer, - (unsigned long)efx); - mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL); - } else { - board->blink_resubmit = false; - if (board->blink_timer.function) - del_timer_sync(&board->blink_timer); - board->init_leds(efx); - } -} - /***************************************************************************** * Support for LM87 sensor chip used on several boards */ @@ -469,7 +435,7 @@ static int sfe4001_init(struct efx_nic *efx) /* 10Xpress has fixed-function LED pins, so there is no board-specific * blink code. */ - efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.set_id_led = tenxpress_set_id_led; efx->board_info.monitor = sfe4001_check_hw; efx->board_info.fini = sfe4001_fini; @@ -546,7 +512,7 @@ static int sfn4111t_init(struct efx_nic *efx) if (!efx->board_info.hwmon_client) return -EIO; - efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.set_id_led = tenxpress_set_id_led; efx->board_info.monitor = sfn4111t_check_hw; efx->board_info.fini = sfn4111t_fini; @@ -619,10 +585,11 @@ static void sfe4002_init_leds(struct efx_nic *efx) falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); } -static void sfe4002_set_id_led(struct efx_nic *efx, bool state) +static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { - falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : - QUAKE_LED_OFF); + falcon_qt202x_set_led( + efx, SFE4002_FAULT_LED, + (mode == EFX_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); } static int sfe4002_check_hw(struct efx_nic *efx) @@ -644,7 +611,6 @@ static int sfe4002_init(struct efx_nic *efx) efx->board_info.monitor = sfe4002_check_hw; efx->board_info.init_leds = sfe4002_init_leds; efx->board_info.set_id_led = sfe4002_set_id_led; - efx->board_info.blink = board_blink; efx->board_info.fini = efx_fini_lm87; return 0; } @@ -683,10 +649,23 @@ static void sfn4112f_init_leds(struct efx_nic *efx) QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); } -static void sfn4112f_set_id_led(struct efx_nic *efx, bool state) +static void sfn4112f_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { - falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, - state ? QUAKE_LED_ON : QUAKE_LED_OFF); + int reg; + + switch (mode) { + case EFX_LED_OFF: + reg = QUAKE_LED_OFF; + break; + case EFX_LED_ON: + reg = QUAKE_LED_ON; + break; + default: + reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; + break; + } + + falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg); } static int sfn4112f_check_hw(struct efx_nic *efx) @@ -703,7 +682,6 @@ static int sfn4112f_init(struct efx_nic *efx) efx->board_info.monitor = sfn4112f_check_hw; efx->board_info.init_leds = sfn4112f_init_leds; efx->board_info.set_id_led = sfn4112f_set_id_led; - efx->board_info.blink = board_blink; efx->board_info.fini = efx_fini_lm87; return 0; } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index bc6fb2b2966..6b05d69429e 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -388,6 +388,12 @@ struct efx_channel { }; +enum efx_led_mode { + EFX_LED_OFF = 0, + EFX_LED_ON = 1, + EFX_LED_DEFAULT = 2 +}; + /** * struct efx_board - board information * @type: Board model type @@ -395,13 +401,9 @@ struct efx_channel { * @minor: Minor rev. (0, 1, ...) * @init: Initialisation function * @init_leds: Sets up board LEDs. May be called repeatedly. - * @set_id_led: Turns the identification LED on or off - * @blink: Starts/stops blinking + * @set_id_led: Set state of identifying LED or revert to automatic function * @monitor: Board-specific health check function * @fini: Cleanup function - * @blink_state: Current blink state - * @blink_resubmit: Blink timer resubmission flag - * @blink_timer: Blink timer * @hwmon_client: I2C client for hardware monitor * @ioexp_client: I2C client for power/port control */ @@ -414,13 +416,9 @@ struct efx_board { * have a separate init callback that happens later than * board init. */ void (*init_leds)(struct efx_nic *efx); - void (*set_id_led) (struct efx_nic *efx, bool state); + void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode); int (*monitor) (struct efx_nic *nic); - void (*blink) (struct efx_nic *efx, bool start); void (*fini) (struct efx_nic *nic); - bool blink_state; - bool blink_resubmit; - struct timer_list blink_timer; struct i2c_client *hwmon_client, *ioexp_client; }; diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index b5150f3bca3..2ad1cec2c72 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -16,7 +16,7 @@ extern struct efx_phy_operations falcon_sfx7101_phy_ops; extern struct efx_phy_operations falcon_sft9001_phy_ops; -extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); +extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed * to boot due to corrupt flash, or some other negative error code. */ diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 560eb18280e..05c0f9acedb 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -228,9 +228,6 @@ static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecm static void qt202x_phy_fini(struct efx_nic *efx) { - /* Clobber the LED if it was blinking */ - efx->board_info.blink(efx, false); - /* Free the context block */ kfree(efx->phy_data); efx->phy_data = NULL; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 19c78d28170..6a8e3ea0381 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -613,21 +613,29 @@ static void tenxpress_phy_fini(struct efx_nic *efx) } -/* Set the RX and TX LEDs and Link LED flashing. The other LEDs - * (which probably aren't wired anyway) are left in AUTO mode */ -void tenxpress_phy_blink(struct efx_nic *efx, bool blink) +/* Override the RX, TX and link LEDs */ +void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { int reg; - if (blink) - reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) | - (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) | - (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN); - else + switch (mode) { + case EFX_LED_OFF: + reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) | + (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) | + (PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN); + break; + case EFX_LED_ON: + reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) | + (PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) | + (PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN); + break; + default: if (efx->phy_type == PHY_TYPE_SFX7101) reg = SFX7101_PMA_PMD_LED_DEFAULT; else reg = SFT9001_PMA_PMD_LED_DEFAULT; + break; + } efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); } -- cgit v1.2.3-70-g09d2 From 981fc1b4b8cc6bfe8c6f0c07052e25738d959c68 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:04:23 +0000 Subject: sfc: Rename efx_board::init_leds to init_phy and use for SFN4111T efx_board::init_leds was introduced as a second stage of initialisation because of the inter-dependency between the board and PHY. We want to move board initialisation into NIC probing, which is too early to use MDIO, so SFN4111T initialisation also needs to be split. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/falcon_boards.c | 43 ++++++++++++++++++++++++----------------- drivers/net/sfc/net_driver.h | 11 ++++------- drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/tenxpress.c | 2 ++ 5 files changed, 33 insertions(+), 27 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 612cd815088..d7705a75516 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1910,7 +1910,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { static struct efx_board efx_dummy_board_info = { .init = efx_port_dummy_op_int, - .init_leds = efx_port_dummy_op_void, + .init_phy = 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, diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index b2505fc5c1f..429d3cd646b 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -499,9 +499,22 @@ static struct i2c_board_info sfn4111t_r5_hwmon_info = { I2C_BOARD_INFO("max6646", 0x4d), }; +static void sfn4111t_init_phy(struct efx_nic *efx) +{ + if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { + if (sft9001_wait_boot(efx) != -EINVAL) + return; + + efx->phy_mode = PHY_MODE_SPECIAL; + efx_stats_disable(efx); + } + + sfn4111t_reset(efx); + sft9001_wait_boot(efx); +} + static int sfn4111t_init(struct efx_nic *efx) { - int i = 0; int rc; efx->board_info.hwmon_client = @@ -512,6 +525,7 @@ static int sfn4111t_init(struct efx_nic *efx) if (!efx->board_info.hwmon_client) return -EIO; + efx->board_info.init_phy = sfn4111t_init_phy; efx->board_info.set_id_led = tenxpress_set_id_led; efx->board_info.monitor = sfn4111t_check_hw; efx->board_info.fini = sfn4111t_fini; @@ -520,20 +534,13 @@ static int sfn4111t_init(struct efx_nic *efx) if (rc) goto fail_hwmon; - do { - 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); - sfn4111t_reset(efx); - } - rc = sft9001_wait_boot(efx); - if (rc == 0) - return 0; - efx->phy_mode = PHY_MODE_SPECIAL; - } while (rc == -EINVAL && ++i < 2); + 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); + + return 0; - device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); fail_hwmon: i2c_unregister_device(efx->board_info.hwmon_client); return rc; @@ -574,7 +581,7 @@ static struct i2c_board_info sfe4002_hwmon_info = { #define SFE4002_RX_LED (0) /* Green */ #define SFE4002_TX_LED (1) /* Amber */ -static void sfe4002_init_leds(struct efx_nic *efx) +static void sfe4002_init_phy(struct efx_nic *efx) { /* Set the TX and RX LEDs to reflect status and activity, and the * fault LED off */ @@ -609,7 +616,7 @@ static int sfe4002_init(struct efx_nic *efx) if (rc) return rc; efx->board_info.monitor = sfe4002_check_hw; - efx->board_info.init_leds = sfe4002_init_leds; + efx->board_info.init_phy = sfe4002_init_phy; efx->board_info.set_id_led = sfe4002_set_id_led; efx->board_info.fini = efx_fini_lm87; return 0; @@ -641,7 +648,7 @@ static struct i2c_board_info sfn4112f_hwmon_info = { #define SFN4112F_ACT_LED 0 #define SFN4112F_LINK_LED 1 -static void sfn4112f_init_leds(struct efx_nic *efx) +static void sfn4112f_init_phy(struct efx_nic *efx) { falcon_qt202x_set_led(efx, SFN4112F_ACT_LED, QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); @@ -680,7 +687,7 @@ static int sfn4112f_init(struct efx_nic *efx) if (rc) return rc; efx->board_info.monitor = sfn4112f_check_hw; - efx->board_info.init_leds = sfn4112f_init_leds; + efx->board_info.init_phy = sfn4112f_init_phy; efx->board_info.set_id_led = sfn4112f_set_id_led; efx->board_info.fini = efx_fini_lm87; return 0; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 6b05d69429e..e1df589dff6 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -399,11 +399,11 @@ enum efx_led_mode { * @type: Board model type * @major: Major rev. ('A', 'B' ...) * @minor: Minor rev. (0, 1, ...) - * @init: Initialisation function - * @init_leds: Sets up board LEDs. May be called repeatedly. + * @init: Allocate resources and initialise peripheral hardware + * @init_phy: Do board-specific PHY initialisation * @set_id_led: Set state of identifying LED or revert to automatic function * @monitor: Board-specific health check function - * @fini: Cleanup function + * @fini: Shut down hardware and free resources * @hwmon_client: I2C client for hardware monitor * @ioexp_client: I2C client for power/port control */ @@ -412,10 +412,7 @@ struct efx_board { int major; int minor; int (*init) (struct efx_nic *nic); - /* As the LEDs are typically attached to the PHY, LEDs - * have a separate init callback that happens later than - * board init. */ - void (*init_leds)(struct efx_nic *efx); + 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); diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 05c0f9acedb..f26684fc8ca 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; - efx->board_info.init_leds(efx); + efx->board_info.init_phy(efx); return rc; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 6a8e3ea0381..2923e3d1e02 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -303,6 +303,8 @@ static int tenxpress_phy_init(struct efx_nic *efx) u16 old_adv, adv; int rc = 0; + efx->board_info.init_phy(efx); + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (!phy_data) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 278c0621fbc4ef52177969edb6f07352da816fdb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:05:12 +0000 Subject: sfc: Make board information explicitly Falcon-specific Rename struct efx_board to struct falcon_board. Introduce and use inline function to look up board info from struct efx_nic, in preparation for moving it. Move board init and fini calls into NIC probe and remove functions. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 25 +++------- drivers/net/sfc/ethtool.c | 6 +-- drivers/net/sfc/falcon.c | 11 +++++ drivers/net/sfc/falcon.h | 5 ++ drivers/net/sfc/falcon_boards.c | 106 ++++++++++++++++++++++------------------ drivers/net/sfc/net_driver.h | 6 +-- drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/tenxpress.c | 2 +- 8 files changed, 88 insertions(+), 75 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d7705a75516..c9f80042669 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1265,7 +1265,7 @@ static void efx_monitor(struct work_struct *data) goto out_requeue; if (!efx->port_enabled) goto out_unlock; - rc = efx->board_info.monitor(efx); + rc = falcon_board(efx)->monitor(efx); if (rc) { EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", (rc == -ERANGE) ? "reported fault" : "failed"); @@ -1908,7 +1908,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { .clear_interrupt = efx_port_dummy_op_void, }; -static struct efx_board efx_dummy_board_info = { +static struct falcon_board efx_dummy_board_info = { .init = efx_port_dummy_op_int, .init_phy = efx_port_dummy_op_void, .set_id_led = efx_port_dummy_op_set_id_led, @@ -2026,10 +2026,6 @@ static void efx_pci_remove_main(struct efx_nic *efx) falcon_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); - - /* Shutdown the board, then the NIC and board state */ - efx->board_info.fini(efx); - efx_fini_napi(efx); efx_remove_all(efx); } @@ -2089,39 +2085,30 @@ static int efx_pci_probe_main(struct efx_nic *efx) if (rc) goto fail2; - /* Initialise the board */ - rc = efx->board_info.init(efx); - if (rc) { - EFX_ERR(efx, "failed to initialise board\n"); - goto fail3; - } - rc = falcon_init_nic(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); - goto fail4; + goto fail3; } rc = efx_init_port(efx); if (rc) { EFX_ERR(efx, "failed to initialise port\n"); - goto fail5; + goto fail4; } efx_init_channels(efx); rc = falcon_init_interrupt(efx); if (rc) - goto fail6; + goto fail5; return 0; - fail6: + fail5: efx_fini_channels(efx); efx_fini_port(efx); - fail5: fail4: - efx->board_info.fini(efx); fail3: efx_fini_napi(efx); fail2: diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 18e02712818..bb415326c73 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -188,14 +188,14 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) struct efx_nic *efx = netdev_priv(net_dev); do { - efx->board_info.set_id_led(efx, EFX_LED_ON); + falcon_board(efx)->set_id_led(efx, EFX_LED_ON); schedule_timeout_interruptible(HZ / 2); - efx->board_info.set_id_led(efx, EFX_LED_OFF); + falcon_board(efx)->set_id_led(efx, EFX_LED_OFF); schedule_timeout_interruptible(HZ / 2); } while (!signal_pending(current) && --count != 0); - efx->board_info.set_id_led(efx, EFX_LED_DEFAULT); + falcon_board(efx)->set_id_led(efx, EFX_LED_DEFAULT); return 0; } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 865638b035b..29e79f77b73 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2877,8 +2877,17 @@ int falcon_probe_nic(struct efx_nic *efx) if (rc) goto fail5; + rc = falcon_board(efx)->init(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise board\n"); + goto fail6; + } + return 0; + fail6: + BUG_ON(i2c_del_adapter(&efx->i2c_adap)); + memset(&efx->i2c_adap, 0, sizeof(efx->i2c_adap)); fail5: falcon_remove_spi_devices(efx); falcon_free_buffer(efx, &efx->irq_status); @@ -3070,6 +3079,8 @@ void falcon_remove_nic(struct efx_nic *efx) struct falcon_nic_data *nic_data = efx->nic_data; int rc; + falcon_board(efx)->fini(efx); + /* Remove I2C adapter and clear it in preparation for a retry */ rc = i2c_del_adapter(&efx->i2c_adap); BUG_ON(rc); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 4dd965774a9..54dad2de22f 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -29,6 +29,11 @@ static inline int falcon_rev(struct efx_nic *efx) return efx->pci_dev->revision; } +static inline struct falcon_board *falcon_board(struct efx_nic *efx) +{ + return &efx->board_info; +} + extern struct efx_nic_type falcon_a_nic_type; extern struct efx_nic_type falcon_b_nic_type; diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 429d3cd646b..af7cd2a0b44 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -65,7 +65,7 @@ static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, goto err; } - efx->board_info.hwmon_client = client; + falcon_board(efx)->hwmon_client = client; return 0; err: @@ -75,12 +75,12 @@ err: static void efx_fini_lm87(struct efx_nic *efx) { - i2c_unregister_device(efx->board_info.hwmon_client); + i2c_unregister_device(falcon_board(efx)->hwmon_client); } static int efx_check_lm87(struct efx_nic *efx, unsigned mask) { - struct i2c_client *client = efx->board_info.hwmon_client; + struct i2c_client *client = falcon_board(efx)->hwmon_client; s32 alarms1, alarms2; /* If link is up then do not monitor temperature */ @@ -189,8 +189,8 @@ static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) static void sfe4001_poweroff(struct efx_nic *efx) { - struct i2c_client *ioexp_client = efx->board_info.ioexp_client; - struct i2c_client *hwmon_client = efx->board_info.hwmon_client; + struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; + struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; /* Turn off all power rails and disable outputs */ i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); @@ -203,8 +203,8 @@ static void sfe4001_poweroff(struct efx_nic *efx) static int sfe4001_poweron(struct efx_nic *efx) { - struct i2c_client *hwmon_client = efx->board_info.hwmon_client; - struct i2c_client *ioexp_client = efx->board_info.ioexp_client; + struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; + struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; unsigned int i, j; int rc; u8 out; @@ -346,7 +346,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 (efx->board_info.type == FALCON_BOARD_SFE4001) + if (falcon_board(efx)->type == FALCON_BOARD_SFE4001) err = sfe4001_poweron(efx); else err = sfn4111t_reset(efx); @@ -363,12 +363,14 @@ static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); static void sfe4001_fini(struct efx_nic *efx) { + struct falcon_board *board = falcon_board(efx); + EFX_INFO(efx, "%s\n", __func__); device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); sfe4001_poweroff(efx); - i2c_unregister_device(efx->board_info.ioexp_client); - i2c_unregister_device(efx->board_info.hwmon_client); + i2c_unregister_device(board->ioexp_client); + i2c_unregister_device(board->hwmon_client); } static int sfe4001_check_hw(struct efx_nic *efx) @@ -387,7 +389,7 @@ static int sfe4001_check_hw(struct efx_nic *efx) * the power undesirably. * We know we can read from the IO expander because we did * it during power-on. Assume failure now is bad news. */ - status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); + status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN); if (status >= 0 && (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) return 0; @@ -409,36 +411,37 @@ static struct i2c_board_info sfe4001_hwmon_info = { */ static int sfe4001_init(struct efx_nic *efx) { + struct falcon_board *board = falcon_board(efx); int rc; #if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) - efx->board_info.hwmon_client = + board->hwmon_client = i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); #else - efx->board_info.hwmon_client = + board->hwmon_client = i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); #endif - if (!efx->board_info.hwmon_client) + if (!board->hwmon_client) return -EIO; /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ - rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, + rc = i2c_smbus_write_byte_data(board->hwmon_client, MAX664X_REG_WLHO, 90); if (rc) goto fail_hwmon; - efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); - if (!efx->board_info.ioexp_client) { + board->ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); + if (!board->ioexp_client) { rc = -EIO; goto fail_hwmon; } /* 10Xpress has fixed-function LED pins, so there is no board-specific * blink code. */ - efx->board_info.set_id_led = tenxpress_set_id_led; + board->set_id_led = tenxpress_set_id_led; - efx->board_info.monitor = sfe4001_check_hw; - efx->board_info.fini = sfe4001_fini; + 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 @@ -459,9 +462,9 @@ static int sfe4001_init(struct efx_nic *efx) fail_on: sfe4001_poweroff(efx); fail_ioexp: - i2c_unregister_device(efx->board_info.ioexp_client); + i2c_unregister_device(board->ioexp_client); fail_hwmon: - i2c_unregister_device(efx->board_info.hwmon_client); + i2c_unregister_device(board->hwmon_client); return rc; } @@ -474,7 +477,7 @@ static int sfn4111t_check_hw(struct efx_nic *efx) return 0; /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ - status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, + status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client, MAX664X_REG_RSL); if (status < 0) return -EIO; @@ -488,7 +491,7 @@ static void sfn4111t_fini(struct efx_nic *efx) EFX_INFO(efx, "%s\n", __func__); device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); - i2c_unregister_device(efx->board_info.hwmon_client); + i2c_unregister_device(falcon_board(efx)->hwmon_client); } static struct i2c_board_info sfn4111t_a0_hwmon_info = { @@ -515,20 +518,21 @@ static void sfn4111t_init_phy(struct efx_nic *efx) static int sfn4111t_init(struct efx_nic *efx) { + struct falcon_board *board = falcon_board(efx); int rc; - efx->board_info.hwmon_client = + board->hwmon_client = i2c_new_device(&efx->i2c_adap, - (efx->board_info.minor < 5) ? + (board->minor < 5) ? &sfn4111t_a0_hwmon_info : &sfn4111t_r5_hwmon_info); - if (!efx->board_info.hwmon_client) + if (!board->hwmon_client) return -EIO; - efx->board_info.init_phy = sfn4111t_init_phy; - efx->board_info.set_id_led = tenxpress_set_id_led; - efx->board_info.monitor = sfn4111t_check_hw; - efx->board_info.fini = sfn4111t_fini; + 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) @@ -542,7 +546,7 @@ static int sfn4111t_init(struct efx_nic *efx) return 0; fail_hwmon: - i2c_unregister_device(efx->board_info.hwmon_client); + i2c_unregister_device(board->hwmon_client); return rc; } @@ -601,10 +605,12 @@ static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) static int sfe4002_check_hw(struct efx_nic *efx) { + struct falcon_board *board = falcon_board(efx); + /* A0 board rev. 4002s report a temperature fault the whole time * (bad sensor) so we mask it out. */ unsigned alarm_mask = - (efx->board_info.major == 0 && efx->board_info.minor == 0) ? + (board->major == 0 && board->minor == 0) ? ~LM87_ALARM_TEMP_EXT1 : ~0; return efx_check_lm87(efx, alarm_mask); @@ -612,13 +618,14 @@ 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; - efx->board_info.monitor = sfe4002_check_hw; - efx->board_info.init_phy = sfe4002_init_phy; - efx->board_info.set_id_led = sfe4002_set_id_led; - efx->board_info.fini = efx_fini_lm87; + 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; } @@ -683,13 +690,15 @@ 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; - efx->board_info.monitor = sfn4112f_check_hw; - efx->board_info.init_phy = sfn4112f_init_phy; - efx->board_info.set_id_led = sfn4112f_set_id_led; - efx->board_info.fini = efx_fini_lm87; + 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; } @@ -714,24 +723,25 @@ static struct falcon_board_data board_data[] = { void falcon_probe_board(struct efx_nic *efx, u16 revision_info) { + struct falcon_board *board = falcon_board(efx); struct falcon_board_data *data = NULL; int i; - efx->board_info.type = FALCON_BOARD_TYPE(revision_info); - efx->board_info.major = FALCON_BOARD_MAJOR(revision_info); - efx->board_info.minor = FALCON_BOARD_MINOR(revision_info); + 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 == efx->board_info.type) + if (board_data[i].type == board->type) data = &board_data[i]; if (data) { EFX_INFO(efx, "board is %s rev %c%d\n", (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ? data->ref_model : data->gen_type, - 'A' + efx->board_info.major, efx->board_info.minor); - efx->board_info.init = data->init; + 'A' + board->major, board->minor); + board->init = data->init; } else { - EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); + EFX_ERR(efx, "unknown board type %d\n", board->type); } } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e1df589dff6..9b84c3ae5ed 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -395,7 +395,7 @@ enum efx_led_mode { }; /** - * struct efx_board - board information + * struct falcon_board - board information * @type: Board model type * @major: Major rev. ('A', 'B' ...) * @minor: Minor rev. (0, 1, ...) @@ -407,7 +407,7 @@ enum efx_led_mode { * @hwmon_client: I2C client for hardware monitor * @ioexp_client: I2C client for power/port control */ -struct efx_board { +struct falcon_board { int type; int major; int minor; @@ -752,7 +752,7 @@ struct efx_nic { unsigned int irq_rx_moderation; struct i2c_adapter i2c_adap; - struct efx_board board_info; + struct falcon_board board_info; enum nic_state state; enum reset_type reset_pending; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index f26684fc8ca..73bc5ad227f 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; - efx->board_info.init_phy(efx); + falcon_board(efx)->init_phy(efx); return rc; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 2923e3d1e02..cb5e0573c7f 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; - efx->board_info.init_phy(efx); + falcon_board(efx)->init_phy(efx); phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (!phy_data) -- cgit v1.2.3-70-g09d2 From 3759433db2f7340ddec3abd55ebb1178600d014e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:05:45 +0000 Subject: sfc: Move struct falcon_board into struct falcon_nic_data Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 11 +---------- drivers/net/sfc/falcon.h | 30 +++++++++++++++++++++++++++++- drivers/net/sfc/falcon_boards.c | 9 +++++++++ drivers/net/sfc/net_driver.h | 27 --------------------------- 4 files changed, 39 insertions(+), 38 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index c9f80042669..b91321126fe 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1878,7 +1878,7 @@ static struct pci_device_id efx_pci_table[] __devinitdata = { /************************************************************************** * - * Dummy PHY/MAC/Board operations + * Dummy PHY/MAC operations * * Can be used for some unimplemented operations * Needed so all function pointers are valid and do not have to be tested @@ -1908,14 +1908,6 @@ static struct efx_phy_operations efx_dummy_phy_operations = { .clear_interrupt = efx_port_dummy_op_void, }; -static struct falcon_board efx_dummy_board_info = { - .init = efx_port_dummy_op_int, - .init_phy = 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, -}; - /************************************************************************** * * Data housekeeping @@ -1944,7 +1936,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->state = STATE_INIT; efx->reset_pending = RESET_TYPE_NONE; strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); - efx->board_info = efx_dummy_board_info; efx->net_dev = net_dev; efx->rx_checksum_enabled = true; diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 46dd43bbbfd..3e9696c12ca 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -30,19 +30,47 @@ static inline int falcon_rev(struct efx_nic *efx) return efx->pci_dev->revision; } +/** + * struct falcon_board - board information + * @type: Board model type + * @major: Major rev. ('A', 'B' ...) + * @minor: Minor rev. (0, 1, ...) + * @init: Allocate resources and initialise peripheral hardware + * @init_phy: Do board-specific PHY initialisation + * @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 + * @hwmon_client: I2C client for hardware monitor + * @ioexp_client: I2C client for power/port control + */ +struct falcon_board { + int 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_client *hwmon_client, *ioexp_client; +}; + /** * struct falcon_nic_data - Falcon NIC state * @pci_dev2: The secondary PCI device if present * @i2c_data: Operations and state for I2C bit-bashing algorithm + * @board: Board state and functions */ struct falcon_nic_data { struct pci_dev *pci_dev2; struct i2c_algo_bit_data i2c_data; + struct falcon_board board; }; static inline struct falcon_board *falcon_board(struct efx_nic *efx) { - return &efx->board_info; + struct falcon_nic_data *data = efx->nic_data; + return &data->board; } extern struct efx_nic_type falcon_a_nic_type; diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index af7cd2a0b44..20aebe07fdf 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -721,12 +721,21 @@ static struct falcon_board_data board_data[] = { sfn4112f_init }, }; +static struct falcon_board falcon_dummy_board = { + .init = efx_port_dummy_op_int, + .init_phy = 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; 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); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 9b84c3ae5ed..fdc9e157e51 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -394,31 +394,6 @@ enum efx_led_mode { EFX_LED_DEFAULT = 2 }; -/** - * struct falcon_board - board information - * @type: Board model type - * @major: Major rev. ('A', 'B' ...) - * @minor: Minor rev. (0, 1, ...) - * @init: Allocate resources and initialise peripheral hardware - * @init_phy: Do board-specific PHY initialisation - * @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 - * @hwmon_client: I2C client for hardware monitor - * @ioexp_client: I2C client for power/port control - */ -struct falcon_board { - int 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_client *hwmon_client, *ioexp_client; -}; - #define STRING_TABLE_LOOKUP(val, member) \ member ## _names[val] @@ -665,7 +640,6 @@ union efx_multicast_hash { * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues * @irq_rx_moderation: IRQ moderation time for RX event queues * @i2c_adap: I2C adapter - * @board_info: Board-level information * @state: Device state flag. Serialised by the rtnl_lock. * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) * @tx_queue: TX DMA queues @@ -752,7 +726,6 @@ struct efx_nic { unsigned int irq_rx_moderation; struct i2c_adapter i2c_adap; - struct falcon_board board_info; enum nic_state state; enum reset_type reset_pending; -- cgit v1.2.3-70-g09d2 From eb50c0d67fe3c5513c717c2dee6d9771c51be703 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:06:30 +0000 Subject: sfc: Gather link state fields in struct efx_nic into new struct efx_link_state Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 12 +++++++----- drivers/net/sfc/ethtool.c | 4 ++-- drivers/net/sfc/falcon.c | 21 +++++++++++---------- drivers/net/sfc/falcon_boards.c | 2 +- drivers/net/sfc/falcon_gmac.c | 13 +++++++------ drivers/net/sfc/falcon_xmac.c | 8 ++++---- drivers/net/sfc/net_driver.h | 26 +++++++++++++++++--------- drivers/net/sfc/qt202x_phy.c | 11 ++++++----- drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/tenxpress.c | 22 ++++++++++++---------- 10 files changed, 68 insertions(+), 53 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b91321126fe..ea31141b173 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -543,6 +543,8 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) */ static void efx_link_status_changed(struct efx_nic *efx) { + struct efx_link_state *link_state = &efx->link_state; + /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure * that no events are triggered between unregister_netdev() and the * driver unloading. A more general condition is that NETDEV_CHANGE @@ -555,19 +557,19 @@ static void efx_link_status_changed(struct efx_nic *efx) return; } - if (efx->link_up != netif_carrier_ok(efx->net_dev)) { + if (link_state->up != netif_carrier_ok(efx->net_dev)) { efx->n_link_state_changes++; - if (efx->link_up) + if (link_state->up) netif_carrier_on(efx->net_dev); else netif_carrier_off(efx->net_dev); } /* Status message for kernel log */ - if (efx->link_up) { + if (link_state->up) { EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n", - efx->link_speed, efx->link_fd ? "full" : "half", + link_state->speed, link_state->fd ? "full" : "half", efx->net_dev->mtu, (efx->promiscuous ? " [PROMISC]" : "")); } else { @@ -758,7 +760,7 @@ static void efx_fini_port(struct efx_nic *efx) efx->phy_op->fini(efx); efx->port_initialized = false; - efx->link_up = false; + efx->link_state.up = false; efx_link_status_changed(efx); } diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index bb415326c73..eb12f201ab0 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -539,7 +539,7 @@ static u32 efx_ethtool_get_link(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - return efx->link_up; + return efx->link_state.up; } static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) @@ -699,7 +699,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, if (EFX_WORKAROUND_11482(efx) && reset) { if (falcon_rev(efx) >= FALCON_REV_B0) { /* Recover by resetting the EM block */ - if (efx->link_up) + if (efx->link_state.up) falcon_drain_tx_fifo(efx); } else { /* Schedule a reset to recover */ diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index ff15b9dd361..6eee4b796c4 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1905,7 +1905,7 @@ static int falcon_reset_macs(struct efx_nic *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_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) + if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) falcon_reset_xaui(efx); return 0; @@ -1939,17 +1939,18 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); efx_writeo(efx, ®, FR_AZ_RX_CFG); - if (!efx->link_up) + if (!efx->link_state.up) falcon_drain_tx_fifo(efx); } void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) { + struct efx_link_state *link_state = &efx->link_state; efx_oword_t reg; int link_speed; bool tx_fc; - switch (efx->link_speed) { + switch (link_state->speed) { case 10000: link_speed = 3; break; case 1000: link_speed = 2; break; case 100: link_speed = 1; break; @@ -1969,7 +1970,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) * discarded. */ if (falcon_rev(efx) >= FALCON_REV_B0) { EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, - !efx->link_up); + !link_state->up); } efx_writeo(efx, ®, FR_AB_MAC_CTRL); @@ -1980,7 +1981,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) /* Transmission of pause frames when RX crosses the threshold is * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ - tx_fc = !!(efx->link_fc & EFX_FC_TX); + tx_fc = !!(efx->link_state.fc & EFX_FC_TX); efx_reado(efx, ®, FR_AZ_RX_CFG); EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc); @@ -2175,11 +2176,11 @@ int falcon_switch_mac(struct efx_nic *efx) /* Internal loopbacks override the phy speed setting */ if (efx->loopback_mode == LOOPBACK_GMAC) { - efx->link_speed = 1000; - efx->link_fd = true; + efx->link_state.speed = 1000; + efx->link_state.fd = true; } else if (LOOPBACK_INTERNAL(efx)) { - efx->link_speed = 10000; - efx->link_fd = true; + efx->link_state.speed = 10000; + efx->link_state.fd = true; } WARN_ON(!mutex_is_locked(&efx->mac_lock)); @@ -2752,7 +2753,7 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) } /* Initial assumed speed */ - efx->link_speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000; + efx->link_state.speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000; return 0; } diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index cdf7a0d6e38..333ccc14e52 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -85,7 +85,7 @@ static int efx_check_lm87(struct efx_nic *efx, unsigned mask) s32 alarms1, alarms2; /* If link is up then do not monitor temperature */ - if (EFX_WORKAROUND_7884(efx) && efx->link_up) + if (EFX_WORKAROUND_7884(efx) && efx->link_state.up) return 0; alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index 8a1b80d1ff2..967f3fb397c 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c @@ -24,16 +24,17 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) { + struct efx_link_state *link_state = &efx->link_state; bool loopback, tx_fc, rx_fc, bytemode; int if_mode; unsigned int max_frame_len; efx_oword_t reg; /* Configuration register 1 */ - tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; - rx_fc = !!(efx->link_fc & EFX_FC_RX); + tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd; + rx_fc = !!(link_state->fc & EFX_FC_RX); loopback = (efx->loopback_mode == LOOPBACK_GMAC); - bytemode = (efx->link_speed == 1000); + bytemode = (link_state->speed == 1000); EFX_POPULATE_OWORD_5(reg, FRF_AB_GM_LOOP, loopback, @@ -50,7 +51,7 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) FRF_AB_GM_IF_MODE, if_mode, FRF_AB_GM_PAD_CRC_EN, 1, FRF_AB_GM_LEN_CHK, 1, - FRF_AB_GM_FD, efx->link_fd, + FRF_AB_GM_FD, link_state->fd, FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */); efx_writeo(efx, ®, FR_AB_GM_CFG2); @@ -101,8 +102,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) /* FIFO configuration register 5 */ efx_reado(efx, ®, FR_AB_GMF_CFG5); EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !efx->link_fd); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !efx->link_fd); + EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd); + EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd); EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0); efx_writeo(efx, ®, FR_AB_GMF_CFG5); udelay(10); diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 7e57b4a54b3..69cb55fc615 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -89,7 +89,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) return; /* We expect xgmii faults if the wireside link is up */ - if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) + if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) return; /* We can only use this interrupt to signal the negative edge of @@ -132,7 +132,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); /* If the link is up, then check the phy side of the xaui link */ - if (efx->link_up && link_ok) + if (efx->link_state.up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) link_ok = efx_mdio_phyxgxs_lane_sync(efx); @@ -143,7 +143,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; - bool rx_fc = !!(efx->link_fc & EFX_FC_RX); + bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX); /* Configure MAC - cut-thru mode is hard wired on */ EFX_POPULATE_DWORD_3(reg, @@ -356,7 +356,7 @@ static void falcon_xmac_irq(struct efx_nic *efx) static void falcon_poll_xmac(struct efx_nic *efx) { - if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) + if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || efx->mac_up) return; falcon_mask_status_intr(efx, false); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 55d45a77a10..f2df32423c9 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -419,7 +419,7 @@ enum phy_type { PHY_TYPE_MAX /* Insert any new items before this */ }; -#define EFX_IS10G(efx) ((efx)->link_speed == 10000) +#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000) enum nic_state { STATE_INIT = 0, @@ -467,6 +467,20 @@ enum efx_mac_type { EFX_XMAC = 2, }; +/** + * struct efx_link_state - Current state of the link + * @up: Link is up + * @fd: Link is full-duplex + * @fc: Actual flow control flags + * @speed: Link speed (Mbps) + */ +struct efx_link_state { + bool up; + bool fd; + enum efx_fc_type fc; + unsigned int speed; +}; + /** * struct efx_mac_operations - Efx MAC operations table * @reconfigure: Reconfigure MAC. Serialised by the mac_lock @@ -691,10 +705,7 @@ union efx_multicast_hash { * @mdio: PHY MDIO interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @mac_up: MAC link state - * @link_up: Link status - * @link_fd: Link is full duplex - * @link_fc: Actualy flow control flags - * @link_speed: Link speed (Mbps) + * @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. * @multicast_hash: Multicast hash table @@ -780,10 +791,7 @@ struct efx_nic { enum efx_phy_mode phy_mode; bool mac_up; - bool link_up; - bool link_fd; - enum efx_fc_type link_fc; - unsigned int link_speed; + struct efx_link_state link_state; unsigned int n_link_state_changes; bool promiscuous; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 73bc5ad227f..8208ac0ffad 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -182,13 +182,14 @@ static void qt202x_phy_poll(struct efx_nic *efx) { int link_up = qt202x_link_ok(efx); /* Simulate a PHY event if link state has changed */ - if (link_up != efx->link_up) + if (link_up != efx->link_state.up) falcon_sim_phy_event(efx); } static void qt202x_phy_reconfigure(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; + struct efx_link_state *link_state = &efx->link_state; if (efx->phy_type == PHY_TYPE_QT2025C) { /* There are several different register bits which can @@ -215,10 +216,10 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx) efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; - efx->link_up = qt202x_link_ok(efx); - efx->link_speed = 10000; - efx->link_fd = true; - efx->link_fc = efx->wanted_fc; + link_state->up = qt202x_link_ok(efx); + link_state->speed = 10000; + link_state->fd = true; + link_state->fc = efx->wanted_fc; } static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 7a9386f97c4..70eb5f13557 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -614,7 +614,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, /* 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 */ - link_up = efx->link_up; + link_up = efx->link_state.up; if (link_up && EFX_IS10G(efx) && !falcon_xaui_link_ok(efx)) link_up = false; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index cb5e0573c7f..b001f38524f 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -503,6 +503,7 @@ static void tenxpress_low_power(struct efx_nic *efx) static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; + struct efx_link_state *link_state = &efx->link_state; struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; @@ -545,37 +546,38 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) phy_data->phy_mode = efx->phy_mode; if (efx->phy_type == PHY_TYPE_SFX7101) { - efx->link_speed = 10000; - efx->link_fd = true; - efx->link_up = sfx7101_link_ok(efx); + link_state->speed = 10000; + link_state->fd = true; + link_state->up = sfx7101_link_ok(efx); } else { efx->phy_op->get_settings(efx, &ecmd); - efx->link_speed = ecmd.speed; - efx->link_fd = ecmd.duplex == DUPLEX_FULL; - efx->link_up = sft9001_link_ok(efx, &ecmd); + link_state->speed = ecmd.speed; + link_state->fd = ecmd.duplex == DUPLEX_FULL; + link_state->up = sft9001_link_ok(efx, &ecmd); } - efx->link_fc = efx_mdio_get_pause(efx); + link_state->fc = efx_mdio_get_pause(efx); } /* Poll PHY for interrupt */ static void tenxpress_phy_poll(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; + struct efx_link_state *link_state = &efx->link_state; bool change = false; if (efx->phy_type == PHY_TYPE_SFX7101) { bool link_ok = sfx7101_link_ok(efx); - if (link_ok != efx->link_up) { + if (link_ok != link_state->up) { change = true; } else { unsigned int link_fc = efx_mdio_get_pause(efx); - if (link_fc != efx->link_fc) + if (link_fc != link_state->fc) change = true; } sfx7101_check_bad_lp(efx, link_ok); } else if (efx->loopback_mode) { bool link_ok = sft9001_link_ok(efx, NULL); - if (link_ok != efx->link_up) + if (link_ok != link_state->up) change = true; } else { int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, -- cgit v1.2.3-70-g09d2 From f5e7adc3d4aa8edab63bb63f0ce5fe92c3dd7604 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:07:30 +0000 Subject: sfc: Combine high-level header files All files that include ethtool.h, rx.h or tx.h are also including efx.h, and there is no good reason to separate out the few declarations they contain. Therefore fold them into efx.h. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 3 --- drivers/net/sfc/efx.h | 27 +++++++++++++++++++++++++-- drivers/net/sfc/ethtool.c | 1 - drivers/net/sfc/ethtool.h | 27 --------------------------- drivers/net/sfc/rx.c | 1 - drivers/net/sfc/rx.h | 26 -------------------------- drivers/net/sfc/selftest.c | 1 - drivers/net/sfc/tx.c | 1 - drivers/net/sfc/tx.h | 25 ------------------------- 9 files changed, 25 insertions(+), 87 deletions(-) delete mode 100644 drivers/net/sfc/ethtool.h delete mode 100644 drivers/net/sfc/rx.h delete mode 100644 drivers/net/sfc/tx.h (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index ea31141b173..cb789953265 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -21,9 +21,6 @@ #include #include #include "net_driver.h" -#include "ethtool.h" -#include "tx.h" -#include "rx.h" #include "efx.h" #include "mdio_10g.h" #include "falcon.h" diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 9d83322e851..3497b036f40 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -23,8 +23,15 @@ #define EFX_MEM_BAR 2 /* TX */ -extern netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - struct sk_buff *skb); +extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); +extern netdev_tx_t +efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +extern netdev_tx_t +efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); extern void efx_stop_queue(struct efx_nic *efx); extern void efx_wake_queue(struct efx_nic *efx); @@ -32,6 +39,15 @@ extern void efx_wake_queue(struct efx_nic *efx); #define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1) /* RX */ +extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); +extern void efx_rx_strategy(struct efx_channel *channel); +extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); +extern void efx_rx_work(struct work_struct *data); +extern void __efx_rx_packet(struct efx_channel *channel, + struct efx_rx_buffer *rx_buf, bool checksummed); extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, unsigned int len, bool checksummed, bool discard); extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay); @@ -50,6 +66,13 @@ 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); +/* Ethtool support */ +extern int efx_ethtool_get_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd); +extern int efx_ethtool_set_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd); +extern const struct ethtool_ops efx_ethtool_ops; + /* Reset handling */ extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, struct ethtool_cmd *ecmd); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index eb12f201ab0..e8afd784e6b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -16,7 +16,6 @@ #include "workarounds.h" #include "selftest.h" #include "efx.h" -#include "ethtool.h" #include "falcon.h" #include "spi.h" #include "mdio_10g.h" diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h deleted file mode 100644 index 295ead40335..00000000000 --- a/drivers/net/sfc/ethtool.h +++ /dev/null @@ -1,27 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005 Fen Systems Ltd. - * Copyright 2006 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_ETHTOOL_H -#define EFX_ETHTOOL_H - -#include "net_driver.h" - -/* - * Ethtool support - */ - -extern int efx_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd); -extern int efx_ethtool_set_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd); - -extern const struct ethtool_ops efx_ethtool_ops; - -#endif /* EFX_ETHTOOL_H */ diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 9f22d15d3d5..accf055ff89 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -16,7 +16,6 @@ #include #include #include "net_driver.h" -#include "rx.h" #include "efx.h" #include "falcon.h" #include "selftest.h" diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h deleted file mode 100644 index 42ee7555a80..00000000000 --- a/drivers/net/sfc/rx.h +++ /dev/null @@ -1,26 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_RX_H -#define EFX_RX_H - -#include "net_driver.h" - -int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); -void efx_remove_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); - -void efx_rx_strategy(struct efx_channel *channel); -void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); -void efx_rx_work(struct work_struct *data); -void __efx_rx_packet(struct efx_channel *channel, - struct efx_rx_buffer *rx_buf, bool checksummed); - -#endif /* EFX_RX_H */ diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index eab8c2e5d5e..afac1cc6bd2 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -20,7 +20,6 @@ #include #include #include "net_driver.h" -#include "ethtool.h" #include "efx.h" #include "falcon.h" #include "selftest.h" diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index a5e541dd8ce..c54fa30e627 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -15,7 +15,6 @@ #include #include #include "net_driver.h" -#include "tx.h" #include "efx.h" #include "falcon.h" #include "workarounds.h" diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h deleted file mode 100644 index e3678962a5b..00000000000 --- a/drivers/net/sfc/tx.h +++ /dev/null @@ -1,25 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_TX_H -#define EFX_TX_H - -#include "net_driver.h" - -int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); -void efx_remove_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); - -netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev); -void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); - -#endif /* EFX_TX_H */ -- cgit v1.2.3-70-g09d2 From c459302db655c1a7fd05fd4266b18990854e8386 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 23 Nov 2009 16:08:17 +0000 Subject: sfc: Log interrupt and reset type names, not numbers Define name tables for these enumerations in a similar way as for loopback. Move the loopback name table together with them. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 51 +++++++++++++++++++++++++++++++++++++++++--- drivers/net/sfc/enum.h | 6 ------ drivers/net/sfc/ethtool.c | 15 +------------ drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/net_driver.h | 19 +++++++++++++++-- drivers/net/sfc/selftest.c | 4 ++-- 6 files changed, 69 insertions(+), 28 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index cb789953265..4787faaf30c 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -25,6 +25,50 @@ #include "mdio_10g.h" #include "falcon.h" +/************************************************************************** + * + * Type name strings + * + ************************************************************************** + */ + +/* Loopback mode names (see LOOPBACK_MODE()) */ +const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; +const char *efx_loopback_mode_names[] = { + [LOOPBACK_NONE] = "NONE", + [LOOPBACK_GMAC] = "GMAC", + [LOOPBACK_XGMII] = "XGMII", + [LOOPBACK_XGXS] = "XGXS", + [LOOPBACK_XAUI] = "XAUI", + [LOOPBACK_GPHY] = "GPHY", + [LOOPBACK_PHYXS] = "PHYXS", + [LOOPBACK_PCS] = "PCS", + [LOOPBACK_PMAPMD] = "PMA/PMD", + [LOOPBACK_NETWORK] = "NETWORK", +}; + +/* Interrupt mode names (see INT_MODE())) */ +const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; +const char *efx_interrupt_mode_names[] = { + [EFX_INT_MODE_MSIX] = "MSI-X", + [EFX_INT_MODE_MSI] = "MSI", + [EFX_INT_MODE_LEGACY] = "legacy", +}; + +const unsigned int efx_reset_type_max = RESET_TYPE_MAX; +const char *efx_reset_type_names[] = { + [RESET_TYPE_INVISIBLE] = "INVISIBLE", + [RESET_TYPE_ALL] = "ALL", + [RESET_TYPE_WORLD] = "WORLD", + [RESET_TYPE_DISABLE] = "DISABLE", + [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", + [RESET_TYPE_INT_ERROR] = "INT_ERROR", + [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", + [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", + [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", + [RESET_TYPE_TX_SKIP] = "TX_SKIP", +}; + #define EFX_MAX_MTU (9 * 1024) /* RX slow fill workqueue. If memory allocation fails in the fast path, @@ -1772,7 +1816,7 @@ static int efx_reset(struct efx_nic *efx) goto out_unlock; } - EFX_INFO(efx, "resetting (%d)\n", method); + EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); efx_reset_down(efx, method, &ecmd); @@ -1851,9 +1895,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) } if (method != type) - EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method); + EFX_LOG(efx, "scheduling %s reset for %s\n", + RESET_TYPE(method), RESET_TYPE(type)); else - EFX_LOG(efx, "scheduling reset (%d)\n", method); + EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method)); efx->reset_pending = method; diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index 60cbc6e1e66..fcd14b73f24 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -40,12 +40,6 @@ enum efx_loopback_mode { #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD -extern const char *efx_loopback_mode_names[]; -#define LOOPBACK_MODE_NAME(mode) \ - STRING_TABLE_LOOKUP(mode, efx_loopback_mode) -#define LOOPBACK_MODE(efx) \ - LOOPBACK_MODE_NAME(efx->loopback_mode) - /* These loopbacks occur within the controller */ #define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ (1 << LOOPBACK_XGMII)| \ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index e8afd784e6b..d8915b95e65 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -20,19 +20,6 @@ #include "spi.h" #include "mdio_10g.h" -const char *efx_loopback_mode_names[] = { - [LOOPBACK_NONE] = "NONE", - [LOOPBACK_GMAC] = "GMAC", - [LOOPBACK_XGMII] = "XGMII", - [LOOPBACK_XGXS] = "XGXS", - [LOOPBACK_XAUI] = "XAUI", - [LOOPBACK_GPHY] = "GPHY", - [LOOPBACK_PHYXS] = "PHYXS", - [LOOPBACK_PCS] = "PCS", - [LOOPBACK_PMAPMD] = "PMA/PMD", - [LOOPBACK_NETWORK] = "NETWORK", -}; - struct ethtool_string { char name[ETH_GSTRING_LEN]; }; @@ -290,7 +277,7 @@ static void efx_fill_test(unsigned int test_index, #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue #define EFX_LOOPBACK_NAME(_mode, _counter) \ - "loopback.%s." _counter, LOOPBACK_MODE_NAME(mode) + "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode) /** * efx_fill_loopback_test - fill in a block of loopback self-test entries diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 6eee4b796c4..41a321b0e8c 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2485,7 +2485,7 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) efx_oword_t glb_ctl_reg_ker; int rc; - EFX_LOG(efx, "performing hardware reset (%d)\n", method); + EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method)); /* Initiate device reset */ if (method == RESET_TYPE_WORLD) { diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index f2df32423c9..ac808d5f24a 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -394,8 +394,23 @@ enum efx_led_mode { EFX_LED_DEFAULT = 2 }; -#define STRING_TABLE_LOOKUP(val, member) \ - member ## _names[val] +#define STRING_TABLE_LOOKUP(val, member) \ + ((val) < member ## _max) ? member ## _names[val] : "(invalid)" + +extern const char *efx_loopback_mode_names[]; +extern const unsigned int efx_loopback_mode_max; +#define LOOPBACK_MODE(efx) \ + STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode) + +extern const char *efx_interrupt_mode_names[]; +extern const unsigned int efx_interrupt_mode_max; +#define INT_MODE(efx) \ + STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode) + +extern const char *efx_reset_type_names[]; +extern const unsigned int efx_reset_type_max; +#define RESET_TYPE(type) \ + STRING_TABLE_LOOKUP(type, efx_reset_type) enum efx_int_mode { /* Be careful if altering to correct macro below */ diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index afac1cc6bd2..63ff295334e 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -175,8 +175,8 @@ static int efx_test_interrupts(struct efx_nic *efx, return -ETIMEDOUT; success: - EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n", - efx->interrupt_mode, efx->last_irq_cpu); + EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx), + efx->last_irq_cpu); tests->interrupt = 1; return 0; } -- cgit v1.2.3-70-g09d2 From 332c1ce9e7b0f9285cba0cf3d32bad87a4f8e40a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:08:52 +0000 Subject: sfc: Strengthen EFX_ASSERT_RESET_SERIALISED Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4787faaf30c..9f3ef387a04 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) -- cgit v1.2.3-70-g09d2 From 44838a447de3b1541cbf845853c4f8999310b0dd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:09:41 +0000 Subject: sfc: Clean up struct falcon_board and struct falcon_board_data 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 Signed-off-by: David S. Miller --- 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(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 9f3ef387a04..dc85efaf15a 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 d8915b95e65..bb9abf24f54 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 2c0be6ccc62..2f1f1fca080 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 ea6ac06fa26..b331889ca46 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 f05c9d330a4..ac1258ea677 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 8208ac0ffad..f9c354e9fc3 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 b001f38524f..a95402d601c 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) -- cgit v1.2.3-70-g09d2 From 1338344a84f5ea60a6689127d2717845e8564b1a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:10:05 +0000 Subject: sfc: Remove unused function efx_flush_queues() Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 13 ------------- drivers/net/sfc/efx.h | 1 - 2 files changed, 14 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index dc85efaf15a..4ebad613e6d 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 3497b036f40..7acf82108a4 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) -- cgit v1.2.3-70-g09d2 From 1dfc5ceacd00365a9089e98643f4b26253d5a6aa Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:11:19 +0000 Subject: sfc: Hold MAC lock for longer in efx_init_port() 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 Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4ebad613e6d..155aa1cca36 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; } -- cgit v1.2.3-70-g09d2 From 55edc6e6ff728681ebc10d418222740705376664 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:11:35 +0000 Subject: sfc: Split MAC stats DMA initiation and completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Steve Hodgson 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 Signed-off-by: David S. Miller --- 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(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 155aa1cca36..41ca5dbb4c4 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 7acf82108a4..01b93f93d31 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 9eec8850210..3ab2daff6b4 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 b331889ca46..61fab0a00cc 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 ac1258ea677..72d1c7834e6 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 967f3fb397c..2aeb3fc0278 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 cf24513900e..e57545de60f 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 d0755ab056f..262aeabdcab 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 a95402d601c..e6232fe2607 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; } -- cgit v1.2.3-70-g09d2 From fe75820b99ff2de713de23252432f0f9d0ca1d35 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:11:45 +0000 Subject: sfc: Move Falcon board/PHY/MAC monitoring code to falcon.c Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- 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(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 41ca5dbb4c4..d17cea9f4e8 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 3ab2daff6b4..c43c5e6f077 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 61fab0a00cc..05e51c2a6d8 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); -- cgit v1.2.3-70-g09d2 From 9007b9fa368b172e6b9a985899080fbebb7d3204 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:12:01 +0000 Subject: sfc: Simplify XMAC link polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Steve Hodgson 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 Signed-off-by: David S. Miller --- 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(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d17cea9f4e8..15616dd9ed4 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 c43c5e6f077..fac534a274c 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 05e51c2a6d8..9ae1b6c8474 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 72d1c7834e6..da750959c61 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 2aeb3fc0278..66d499cc23f 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 e57545de60f..784260f63d4 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 262aeabdcab..cc1a97b0a0d 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 63ff295334e..23e646a6c2c 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); -- cgit v1.2.3-70-g09d2 From 8be4f3e6f7b670529bd67aa1f0319bec1e29ebcf Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Nov 2009 16:12:16 +0000 Subject: sfc: Change MAC promiscuity and multicast hash at the same time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Steve Hodgson 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 Signed-off-by: David S. Miller --- 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(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 15616dd9ed4..1009d1eeba8 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 fac534a274c..e26043eb01b 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 9ae1b6c8474..c70bb084216 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 cc1a97b0a0d..ead1c982365 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 -- cgit v1.2.3-70-g09d2 From fdaa9aed21c8c8b529f3c94a5ffa138bf3360b75 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Sat, 28 Nov 2009 05:34:05 +0000 Subject: sfc: Simplify PHY polling Falcon can generate events for LASI interrupts from the PHY, but in practice we have never implemented this in reference designs. Instead we have polled, inserted the appropriate events, and then handled the events later. This is a waste of time and code. Instead, make PHY poll functions update the link state synchronously and report whether it changed. We can still make use of the LASI registers as a shortcut on the SFT9001. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 35 +++++----------------- drivers/net/sfc/efx.h | 3 ++ drivers/net/sfc/falcon.c | 69 +++++++++++++++++++++++++++----------------- drivers/net/sfc/falcon.h | 1 - drivers/net/sfc/net_driver.h | 24 ++++++++------- drivers/net/sfc/qt202x_phy.c | 26 ++++++----------- drivers/net/sfc/tenxpress.c | 69 +++++++++++++++++--------------------------- 7 files changed, 103 insertions(+), 124 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 1009d1eeba8..b5a7e91590d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -583,7 +583,7 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) * netif_carrier_on/off) of the link status, and also maintains the * link status's stop on the port's TX queue. */ -static void efx_link_status_changed(struct efx_nic *efx) +void efx_link_status_changed(struct efx_nic *efx) { struct efx_link_state *link_state = &efx->link_state; @@ -675,19 +675,6 @@ void efx_reconfigure_port(struct efx_nic *efx) mutex_unlock(&efx->mac_lock); } -/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() - * we don't efx_reconfigure_port() if the port is disabled. Care is taken - * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ -static void efx_phy_work(struct work_struct *data) -{ - struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); - - mutex_lock(&efx->mac_lock); - if (efx->port_enabled) - __efx_reconfigure_port(efx); - 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. */ @@ -768,9 +755,6 @@ fail1: return rc; } -/* Allow efx_reconfigure_port() to be scheduled, and close the window - * between efx_stop_port and efx_flush_all whereby a previously scheduled - * efx_phy_work()/efx_mac_work() may have been cancelled */ static void efx_start_port(struct efx_nic *efx) { EFX_LOG(efx, "start port\n"); @@ -787,10 +771,7 @@ static void efx_start_port(struct efx_nic *efx) mutex_unlock(&efx->mac_lock); } -/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, - * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work - * and efx_mac_work may still be scheduled via NAPI processing until - * efx_flush_all() is called */ +/* Prevent efx_mac_work() and efx_monitor() from working */ static void efx_stop_port(struct efx_nic *efx) { EFX_LOG(efx, "stop port\n"); @@ -1188,8 +1169,6 @@ static void efx_flush_all(struct efx_nic *efx) /* Stop scheduled port reconfigurations */ cancel_work_sync(&efx->mac_work); - cancel_work_sync(&efx->phy_work); - } /* Quiesce hardware and software without bringing the link down. @@ -1227,7 +1206,7 @@ static void efx_stop_all(struct efx_nic *efx) * window to loose phy events */ efx_stop_port(efx); - /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ + /* Flush efx_mac_work(), refill_workqueue, monitor_work */ efx_flush_all(efx); /* Isolate the MAC from the TX and RX engines, so that queue @@ -1907,6 +1886,10 @@ void efx_port_dummy_op_void(struct efx_nic *efx) {} void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { } +bool efx_port_dummy_op_poll(struct efx_nic *efx) +{ + return false; +} static struct efx_mac_operations efx_dummy_mac_operations = { .reconfigure = efx_port_dummy_op_void, @@ -1915,9 +1898,8 @@ static struct efx_mac_operations efx_dummy_mac_operations = { static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_void, - .poll = efx_port_dummy_op_void, + .poll = efx_port_dummy_op_poll, .fini = efx_port_dummy_op_void, - .clear_interrupt = efx_port_dummy_op_void, }; /************************************************************************** @@ -1957,7 +1939,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; efx->mdio.dev = net_dev; - INIT_WORK(&efx->phy_work, efx_phy_work); INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 01b93f93d31..15edda2a224 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -90,6 +90,7 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); extern void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); +extern bool efx_port_dummy_op_poll(struct efx_nic *efx); /* MTD */ #ifdef CONFIG_SFC_MTD @@ -113,4 +114,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel) napi_schedule(&channel->napi_str); } +extern void efx_link_status_changed(struct efx_nic *efx); + #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index e26043eb01b..e16faad7028 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -893,8 +893,7 @@ static void falcon_handle_global_event(struct efx_channel *channel, if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { - efx->phy_op->clear_interrupt(efx); - queue_work(efx->workqueue, &efx->phy_work); + /* Ignored */ handled = true; } @@ -1140,20 +1139,6 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) falcon_generate_event(channel, &test_event); } -void falcon_sim_phy_event(struct efx_nic *efx) -{ - efx_qword_t phy_event; - - EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE, - FSE_AZ_EV_CODE_GLOBAL_EV); - if (EFX_IS10G(efx)) - EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1); - else - EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1); - - falcon_generate_event(&efx->channel[0], &phy_event); -} - /************************************************************************** * * Flush handling @@ -2063,6 +2048,25 @@ static void falcon_stats_timer_func(unsigned long context) spin_unlock(&efx->stats_lock); } +static bool falcon_loopback_link_poll(struct efx_nic *efx) +{ + struct efx_link_state old_state = efx->link_state; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + efx->link_state.up = true; + + if (efx->loopback_mode == LOOPBACK_GMAC) + efx->link_state.speed = 1000; + else + efx->link_state.speed = 10000; + + return !efx_link_state_equal(&efx->link_state, &old_state); +} + /************************************************************************** * * PHY access via GMII @@ -2225,15 +2229,6 @@ int falcon_switch_mac(struct efx_nic *efx) /* Don't try to fetch MAC stats while we're switching MACs */ falcon_stop_nic_stats(efx); - /* Internal loopbacks override the phy speed setting */ - if (efx->loopback_mode == LOOPBACK_GMAC) { - efx->link_state.speed = 1000; - efx->link_state.fd = true; - } else if (LOOPBACK_INTERNAL(efx)) { - efx->link_state.speed = 10000; - efx->link_state.fd = true; - } - WARN_ON(!mutex_is_locked(&efx->mac_lock)); efx->mac_op = (EFX_IS10G(efx) ? &falcon_xmac_operations : &falcon_gmac_operations); @@ -2610,16 +2605,36 @@ fail5: void falcon_monitor(struct efx_nic *efx) { + bool link_changed; int rc; + BUG_ON(!mutex_is_locked(&efx->mac_lock)); + 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_reconfigure_port(efx); } - efx->phy_op->poll(efx); + + if (LOOPBACK_INTERNAL(efx)) + link_changed = falcon_loopback_link_poll(efx); + else + link_changed = efx->phy_op->poll(efx); + + if (link_changed) { + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_switch_mac(efx); + efx->mac_op->reconfigure(efx); + + falcon_start_nic_stats(efx); + + efx_link_status_changed(efx); + } + if (EFX_IS10G(efx)) falcon_poll_xmac(efx); } diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index c70bb084216..a561f6758bc 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -145,7 +145,6 @@ extern int falcon_init_interrupt(struct efx_nic *efx); extern void falcon_enable_interrupts(struct efx_nic *efx); extern void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic); -extern void falcon_sim_phy_event(struct efx_nic *efx); extern void falcon_generate_interrupt(struct efx_nic *efx); extern void falcon_set_int_moderation(struct efx_channel *channel); extern void falcon_disable_interrupts(struct efx_nic *efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ead1c982365..fb9327c5ea5 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -503,6 +503,13 @@ struct efx_link_state { unsigned int speed; }; +static inline bool efx_link_state_equal(const struct efx_link_state *left, + const struct efx_link_state *right) +{ + return left->up == right->up && left->fd == right->fd && + left->fc == right->fc && left->speed == right->speed; +} + /** * struct efx_mac_operations - Efx MAC operations table * @reconfigure: Reconfigure MAC. Serialised by the mac_lock @@ -520,8 +527,8 @@ struct efx_mac_operations { * @init: Initialise PHY * @fini: Shut down PHY * @reconfigure: Reconfigure PHY (e.g. for new link parameters) - * @clear_interrupt: Clear down interrupt - * @poll: Poll for hardware state. Serialised by the mac_lock. + * @poll: Update @link_state and report whether it changed. + * Serialised by the mac_lock. * @get_settings: Get ethtool settings. Serialised by the mac_lock. * @set_settings: Set ethtool settings. Serialised by the mac_lock. * @set_npage_adv: Set abilities advertised in (Extended) Next Page @@ -538,8 +545,7 @@ struct efx_phy_operations { int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); void (*reconfigure) (struct efx_nic *efx); - void (*clear_interrupt) (struct efx_nic *efx); - void (*poll) (struct efx_nic *efx); + bool (*poll) (struct efx_nic *efx); void (*get_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); int (*set_settings) (struct efx_nic *efx, @@ -700,10 +706,10 @@ union efx_multicast_hash { * @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(), efx_monitor(), - * efx_phy_work(), and efx_mac_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. + * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and + * efx_mac_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 @@ -729,7 +735,6 @@ union efx_multicast_hash { * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @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 changing MAC promiscuity and multicast hash * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask @@ -802,7 +807,6 @@ struct efx_nic { enum phy_type phy_type; spinlock_t phy_lock; - struct work_struct phy_work; struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index f9c354e9fc3..1b174c3e6c1 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -167,29 +167,26 @@ static int qt202x_phy_init(struct efx_nic *efx) return rc; } -static void qt202x_phy_clear_interrupt(struct efx_nic *efx) -{ - /* Read to clear link status alarm */ - efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); -} - static int qt202x_link_ok(struct efx_nic *efx) { return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS); } -static void qt202x_phy_poll(struct efx_nic *efx) +static bool qt202x_phy_poll(struct efx_nic *efx) { - int link_up = qt202x_link_ok(efx); - /* Simulate a PHY event if link state has changed */ - if (link_up != efx->link_state.up) - falcon_sim_phy_event(efx); + bool was_up = efx->link_state.up; + + efx->link_state.up = qt202x_link_ok(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + + return efx->link_state.up != was_up; } static void qt202x_phy_reconfigure(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; if (efx->phy_type == PHY_TYPE_QT2025C) { /* There are several different register bits which can @@ -216,10 +213,6 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx) efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; - link_state->up = qt202x_link_ok(efx); - link_state->speed = 10000; - link_state->fd = true; - link_state->fc = efx->wanted_fc; } static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) @@ -240,7 +233,6 @@ struct efx_phy_operations falcon_qt202x_phy_ops = { .reconfigure = qt202x_phy_reconfigure, .poll = qt202x_phy_poll, .fini = qt202x_phy_fini, - .clear_interrupt = qt202x_phy_clear_interrupt, .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, .mmds = QT202X_REQUIRED_DEVS, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index e6232fe2607..1bd79650a00 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -503,7 +503,6 @@ static void tenxpress_low_power(struct efx_nic *efx) static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; @@ -544,53 +543,41 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; - - if (efx->phy_type == PHY_TYPE_SFX7101) { - link_state->speed = 10000; - link_state->fd = true; - link_state->up = sfx7101_link_ok(efx); - } else { - efx->phy_op->get_settings(efx, &ecmd); - link_state->speed = ecmd.speed; - link_state->fd = ecmd.duplex == DUPLEX_FULL; - link_state->up = sft9001_link_ok(efx, &ecmd); - } - link_state->fc = efx_mdio_get_pause(efx); } -/* Poll PHY for interrupt */ -static void tenxpress_phy_poll(struct efx_nic *efx) +static void +tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); + +/* Poll for link state changes */ +static bool tenxpress_phy_poll(struct efx_nic *efx) { - struct tenxpress_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; - bool change = false; + struct efx_link_state old_state = efx->link_state; if (efx->phy_type == PHY_TYPE_SFX7101) { - bool link_ok = sfx7101_link_ok(efx); - if (link_ok != link_state->up) { - change = true; - } else { - unsigned int link_fc = efx_mdio_get_pause(efx); - if (link_fc != link_state->fc) - change = true; - } - sfx7101_check_bad_lp(efx, link_ok); - } else if (efx->loopback_mode) { - bool link_ok = sft9001_link_ok(efx, NULL); - if (link_ok != link_state->up) - change = true; + efx->link_state.up = sfx7101_link_ok(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx_mdio_get_pause(efx); + + sfx7101_check_bad_lp(efx, efx->link_state.up); } else { - int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, - MDIO_PMA_LASI_STAT); - if (status & MDIO_PMA_LASI_LSALARM) - change = true; - } + struct ethtool_cmd ecmd; - if (change) - falcon_sim_phy_event(efx); + /* Check the LASI alarm first */ + if (efx->loopback_mode == LOOPBACK_NONE && + !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & + MDIO_PMA_LASI_LSALARM)) + return false; - if (phy_data->phy_mode != PHY_MODE_NORMAL) - return; + tenxpress_get_settings(efx, &ecmd); + + efx->link_state.up = sft9001_link_ok(efx, &ecmd); + efx->link_state.speed = ecmd.speed; + efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); + efx->link_state.fc = efx_mdio_get_pause(efx); + } + + return !efx_link_state_equal(&efx->link_state, &old_state); } static void tenxpress_phy_fini(struct efx_nic *efx) @@ -818,7 +805,6 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = efx_port_dummy_op_void, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sfx7101_set_npage_adv, @@ -835,7 +821,6 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = efx_port_dummy_op_void, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sft9001_set_npage_adv, -- cgit v1.2.3-70-g09d2 From ab86746175a5e1379abb9c7c38522af4d3176f57 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Sat, 28 Nov 2009 05:34:44 +0000 Subject: sfc: Replace MDIO spinlock with mutex We never use MDIO in atomic context, so we don't need to spin. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/falcon.c | 12 ++++++------ drivers/net/sfc/net_driver.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b5a7e91590d..6338ad8dbfb 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1922,7 +1922,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, /* Initialise common structures */ memset(efx, 0, sizeof(*efx)); spin_lock_init(&efx->biu_lock); - spin_lock_init(&efx->phy_lock); + mutex_init(&efx->mdio_lock); mutex_init(&efx->spi_lock); INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index e16faad7028..372dbbc7240 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2110,7 +2110,7 @@ static int falcon_mdio_write(struct net_device *net_dev, EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", prtad, devad, addr, value); - spin_lock_bh(&efx->phy_lock); + mutex_lock(&efx->mdio_lock); /* Check MDIO not currently being accessed */ rc = falcon_gmii_wait(efx); @@ -2145,8 +2145,8 @@ static int falcon_mdio_write(struct net_device *net_dev, udelay(10); } - out: - spin_unlock_bh(&efx->phy_lock); +out: + mutex_unlock(&efx->mdio_lock); return rc; } @@ -2158,7 +2158,7 @@ static int falcon_mdio_read(struct net_device *net_dev, efx_oword_t reg; int rc; - spin_lock_bh(&efx->phy_lock); + mutex_lock(&efx->mdio_lock); /* Check MDIO not currently being accessed */ rc = falcon_gmii_wait(efx); @@ -2194,8 +2194,8 @@ static int falcon_mdio_read(struct net_device *net_dev, prtad, devad, addr, rc); } - out: - spin_unlock_bh(&efx->phy_lock); +out: + mutex_unlock(&efx->mdio_lock); return rc; } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index fb9327c5ea5..0aeaeda9db7 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -724,7 +724,7 @@ union efx_multicast_hash { * @mac_op: MAC interface * @mac_address: Permanent MAC address * @phy_type: PHY type - * @phy_lock: PHY access lock + * @mdio_lock: MDIO lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) * @mdio: PHY MDIO interface @@ -806,7 +806,7 @@ struct efx_nic { unsigned char mac_address[ETH_ALEN]; enum phy_type phy_type; - spinlock_t phy_lock; + struct mutex mdio_lock; struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; -- cgit v1.2.3-70-g09d2 From b895d73e9836fccc402e48a8f63e6805d2edc87b Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Sat, 28 Nov 2009 05:35:00 +0000 Subject: sfc: Always start Falcon using the XMAC The strap bits are only important on Falcon A and all production boards using it have fixed-speed 10G PHYs. Replace dummy MAC operations with default MAC operations. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 6 +----- drivers/net/sfc/falcon.c | 15 ++++++++++++--- drivers/net/sfc/net_driver.h | 3 +++ 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 6338ad8dbfb..bed45a59987 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1891,10 +1891,6 @@ bool efx_port_dummy_op_poll(struct efx_nic *efx) return false; } -static struct efx_mac_operations efx_dummy_mac_operations = { - .reconfigure = efx_port_dummy_op_void, -}; - static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_void, @@ -1936,7 +1932,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); - efx->mac_op = &efx_dummy_mac_operations; + efx->mac_op = type->default_mac_ops; efx->phy_op = &efx_dummy_phy_operations; efx->mdio.dev = net_dev; INIT_WORK(&efx->mac_work, efx_mac_work); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 372dbbc7240..9c4f8985aa7 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2291,6 +2291,10 @@ int falcon_probe_port(struct efx_nic *efx) efx->mdio.mdio_read = falcon_mdio_read; efx->mdio.mdio_write = falcon_mdio_write; + /* Initial assumption */ + efx->link_state.speed = 10000; + efx->link_state.fd = true; + /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ if (falcon_rev(efx) >= FALCON_REV_B0) efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; @@ -2809,6 +2813,10 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; case FALCON_REV_A1: + if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { + EFX_ERR(efx, "Falcon rev A1 1G not supported\n"); + return -ENODEV; + } if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); return -ENODEV; @@ -2823,9 +2831,6 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; } - /* Initial assumed speed */ - efx->link_state.speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000; - return 0; } @@ -3238,6 +3243,8 @@ void falcon_stop_nic_stats(struct efx_nic *efx) */ struct efx_nic_type falcon_a_nic_type = { + .default_mac_ops = &falcon_xmac_operations, + .mem_map_size = 0x20000, .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, @@ -3251,6 +3258,8 @@ struct efx_nic_type falcon_a_nic_type = { }; struct efx_nic_type falcon_b_nic_type = { + .default_mac_ops = &falcon_xmac_operations, + /* Map everything up to and including the RSS indirection * table. Don't map MSI-X table, MSI-X PBA since Linux * requires that they not be mapped. */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 0aeaeda9db7..57f861468c1 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -843,6 +843,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) /** * struct efx_nic_type - Efx device type definition + * @default_mac_ops: efx_mac_operations to set at startup * @mem_map_size: Memory BAR mapped size * @txd_ptr_tbl_base: TX descriptor ring base address * @rxd_ptr_tbl_base: RX descriptor ring base address @@ -857,6 +858,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * descriptors */ struct efx_nic_type { + struct efx_mac_operations *default_mac_ops; + unsigned int mem_map_size; unsigned int txd_ptr_tbl_base; unsigned int rxd_ptr_tbl_base; -- cgit v1.2.3-70-g09d2 From daeda6309e1382819a8f8bab548560742ac26cc2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 28 Nov 2009 05:36:04 +0000 Subject: sfc: Decouple NIC revision number from Falcon PCI revision number Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 4 +-- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/falcon.c | 68 ++++++++++++++++++++----------------------- drivers/net/sfc/falcon.h | 16 +++++----- drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/net_driver.h | 2 ++ drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/workarounds.h | 4 +-- 8 files changed, 48 insertions(+), 52 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index bed45a59987..f5e81114270 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1863,9 +1863,9 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) /* PCI device ID table */ static struct pci_device_id efx_pci_table[] __devinitdata = { {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), - .driver_data = (unsigned long) &falcon_a_nic_type}, + .driver_data = (unsigned long) &falcon_a1_nic_type}, {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), - .driver_data = (unsigned long) &falcon_b_nic_type}, + .driver_data = (unsigned long) &falcon_b0_nic_type}, {0} /* end of list */ }; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 6515b8a4b38..5d2e186e671 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -683,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, * and fix it be cycling transmit flow control on this end. */ reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); if (EFX_WORKAROUND_11482(efx) && reset) { - if (falcon_rev(efx) == FALCON_REV_B0) { + if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { /* Recover by resetting the EM block */ if (efx->link_state.up) falcon_drain_tx_fifo(efx); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index b186fd2c9b6..7c9c9c93595 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -111,7 +111,7 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); #define FALCON_RX_FLUSH_COUNT 4 #define FALCON_IS_DUAL_FUNC(efx) \ - (falcon_rev(efx) < FALCON_REV_B0) + (efx_nic_rev(efx) < EFX_REV_FALCON_B0) /************************************************************************** * @@ -447,7 +447,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue) FRF_AZ_TX_DESCQ_TYPE, 0, FRF_BZ_TX_NON_IP_DROP_DIS, 1); - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, @@ -457,7 +457,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue) efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, tx_queue->queue); - if (falcon_rev(efx) < FALCON_REV_B0) { + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { efx_oword_t reg; /* Only 128 bits in this register */ @@ -574,7 +574,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; - bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; + bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0; bool iscsi_digest_en = is_b0; EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", @@ -752,7 +752,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR); rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR); rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC); - rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ? + rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ? 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB)); rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR); @@ -897,13 +897,13 @@ static void falcon_handle_global_event(struct efx_channel *channel, handled = true; } - if ((falcon_rev(efx) >= FALCON_REV_B0) && + if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) && EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { efx->xmac_poll_required = true; handled = true; } - if (falcon_rev(efx) <= FALCON_REV_A1 ? + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { EFX_ERR(efx, "channel %d seen global RX_RESET " @@ -1531,7 +1531,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx) unsigned long offset; efx_dword_t dword; - if (falcon_rev(efx) < FALCON_REV_B0) + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) return; for (offset = FR_BZ_RX_INDIRECTION_TBL; @@ -1554,7 +1554,7 @@ int falcon_init_interrupt(struct efx_nic *efx) if (!EFX_INT_MODE_USE_MSI(efx)) { irq_handler_t handler; - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) handler = falcon_legacy_interrupt_b0; else handler = falcon_legacy_interrupt_a1; @@ -1601,7 +1601,7 @@ void falcon_fini_interrupt(struct efx_nic *efx) } /* ACK legacy interrupt */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) efx_reado(efx, ®, FR_BZ_INT_ISR0); else falcon_irq_ack_a1(efx); @@ -1841,7 +1841,7 @@ static int falcon_reset_macs(struct efx_nic *efx) efx_oword_t reg; int count; - if (falcon_rev(efx) < FALCON_REV_B0) { + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { /* It's not safe to use GLB_CTL_REG to reset the * macs, so instead use the internal MAC resets */ @@ -1917,7 +1917,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx) { efx_oword_t reg; - if ((falcon_rev(efx) < FALCON_REV_B0) || + if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) || (efx->loopback_mode != LOOPBACK_NONE)) return; @@ -1933,7 +1933,7 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) { efx_oword_t reg; - if (falcon_rev(efx) < FALCON_REV_B0) + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) return; /* Isolate the MAC -> RX */ @@ -1970,7 +1970,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) FRF_AB_MAC_SPEED, link_speed); /* On B0, MAC backpressure can be disabled and packets get * discarded. */ - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, !link_state->up); } @@ -1988,7 +1988,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc); /* Unisolate the MAC -> RX */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); efx_writeo(efx, ®, FR_AZ_RX_CFG); } @@ -2207,7 +2207,7 @@ static void falcon_clock_mac(struct efx_nic *efx) /* 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) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_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); @@ -2296,7 +2296,7 @@ int falcon_probe_port(struct efx_nic *efx) efx->link_state.fd = true; /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; else efx->wanted_fc = EFX_FC_RX; @@ -2806,13 +2806,13 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); - switch (falcon_rev(efx)) { - case FALCON_REV_A0: - case 0xff: - EFX_ERR(efx, "Falcon rev A0 not supported\n"); - return -ENODEV; + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { + u8 pci_rev = efx->pci_dev->revision; - case FALCON_REV_A1: + if ((pci_rev == 0xff) || (pci_rev == 0)) { + EFX_ERR(efx, "Falcon rev A0 not supported\n"); + return -ENODEV; + } if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { EFX_ERR(efx, "Falcon rev A1 1G not supported\n"); return -ENODEV; @@ -2821,14 +2821,6 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); return -ENODEV; } - break; - - case FALCON_REV_B0: - break; - - default: - EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx)); - return -ENODEV; } return 0; @@ -2991,7 +2983,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) efx_oword_t reg; efx_reado(efx, ®, FR_AZ_RX_CFG); - if (falcon_rev(efx) <= FALCON_REV_A1) { + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { /* Data FIFO size is 5.5K */ if (data_xon_thr < 0) data_xon_thr = 512 >> 8; @@ -3037,7 +3029,7 @@ int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_AB_NIC_STAT); /* Set the source of the GMAC clock */ - if (falcon_rev(efx) == FALCON_REV_B0) { + if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { efx_reado(efx, &temp, FR_AB_GPIO_CTL); EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); efx_writeo(efx, &temp, FR_AB_GPIO_CTL); @@ -3128,7 +3120,7 @@ int falcon_init_nic(struct efx_nic *efx) /* Prefetch threshold 2 => fetch when descriptor cache half empty */ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); /* Squash TX of packets of 16 bytes or less */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); @@ -3142,7 +3134,7 @@ int falcon_init_nic(struct efx_nic *efx) falcon_init_rx_cfg(efx); /* Set destination of both TX and RX Flush events */ - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); efx_writeo(efx, &temp, FR_BZ_DP_CTRL); } @@ -3242,9 +3234,10 @@ void falcon_stop_nic_stats(struct efx_nic *efx) ************************************************************************** */ -struct efx_nic_type falcon_a_nic_type = { +struct efx_nic_type falcon_a1_nic_type = { .default_mac_ops = &falcon_xmac_operations, + .revision = EFX_REV_FALCON_A1, .mem_map_size = 0x20000, .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, @@ -3257,9 +3250,10 @@ struct efx_nic_type falcon_a_nic_type = { .phys_addr_channels = 4, }; -struct efx_nic_type falcon_b_nic_type = { +struct efx_nic_type falcon_b0_nic_type = { .default_mac_ops = &falcon_xmac_operations, + .revision = EFX_REV_FALCON_B0, /* Map everything up to and including the RSS indirection * table. Don't map MSI-X table, MSI-X PBA since Linux * requires that they not be mapped. */ diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index a561f6758bc..81196a0fb50 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -19,15 +19,15 @@ * Falcon hardware control */ -enum falcon_revision { - FALCON_REV_A0 = 0, - FALCON_REV_A1 = 1, - FALCON_REV_B0 = 2, +enum { + EFX_REV_FALCON_A0 = 0, + EFX_REV_FALCON_A1 = 1, + EFX_REV_FALCON_B0 = 2, }; -static inline int falcon_rev(struct efx_nic *efx) +static inline int efx_nic_rev(struct efx_nic *efx) { - return efx->pci_dev->revision; + return efx->type->revision; } /** @@ -95,8 +95,8 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) return &data->board; } -extern struct efx_nic_type falcon_a_nic_type; -extern struct efx_nic_type falcon_b_nic_type; +extern struct efx_nic_type falcon_a1_nic_type; +extern struct efx_nic_type falcon_b0_nic_type; /************************************************************************** * diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 784260f63d4..1523efdcefe 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -89,7 +89,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) return; /* We expect xgmii faults if the wireside link is up */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ca7dff2269d..a42a0516d04 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -844,6 +844,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) /** * struct efx_nic_type - Efx device type definition * @default_mac_ops: efx_mac_operations to set at startup + * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size * @txd_ptr_tbl_base: TX descriptor ring base address * @rxd_ptr_tbl_base: RX descriptor ring base address @@ -860,6 +861,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) struct efx_nic_type { struct efx_mac_operations *default_mac_ops; + int revision; unsigned int mem_map_size; unsigned int txd_ptr_tbl_base; unsigned int rxd_ptr_tbl_base; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 15806078971..74e84afd5b6 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -125,7 +125,7 @@ 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) + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) return 0; rc = falcon_test_registers(efx); diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 209ee1e9094..021d0d2d97f 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -16,8 +16,8 @@ */ #define EFX_WORKAROUND_ALWAYS(efx) 1 -#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) -#define EFX_WORKAROUND_FALCON_AB(efx) (falcon_rev(efx) <= FALCON_REV_B0) +#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) +#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ (efx)->phy_type == PHY_TYPE_SFT9001B) -- cgit v1.2.3-70-g09d2 From ef2b90ee4dba7a3d9001f1f0003b860b39a4aaae Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 03:42:31 +0000 Subject: sfc: Move Falcon NIC operations to efx_nic_type This is preparation for adding differing implementations for new NICs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 44 +++++++++++++----------- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/falcon.c | 79 ++++++++++++++++++++++++++++---------------- drivers/net/sfc/falcon.h | 12 ------- drivers/net/sfc/net_driver.h | 29 ++++++++++++++++ drivers/net/sfc/selftest.c | 2 +- 6 files changed, 105 insertions(+), 63 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index f5e81114270..73ab246d9f2 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -274,14 +274,14 @@ static int efx_poll(struct napi_struct *napi, int budget) irq_adapt_low_thresh)) { if (channel->irq_moderation > 1) { channel->irq_moderation -= 1; - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); } } else if (unlikely(channel->irq_mod_score > irq_adapt_high_thresh)) { if (channel->irq_moderation < efx->irq_rx_moderation) { channel->irq_moderation += 1; - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); } } channel->irq_count = 0; @@ -637,7 +637,7 @@ void __efx_reconfigure_port(struct efx_nic *efx) netif_addr_unlock_bh(efx->net_dev); } - falcon_stop_nic_stats(efx); + efx->type->stop_stats(efx); falcon_deconfigure_mac_wrapper(efx); /* Reconfigure the PHY, disabling transmit in mac level loopback. */ @@ -652,7 +652,7 @@ void __efx_reconfigure_port(struct efx_nic *efx) efx->mac_op->reconfigure(efx); - falcon_start_nic_stats(efx); + efx->type->start_stats(efx); /* Inform kernel of loss/gain of carrier */ efx_link_status_changed(efx); @@ -684,7 +684,7 @@ static void efx_mac_work(struct work_struct *data) mutex_lock(&efx->mac_lock); if (efx->port_enabled) { - falcon_push_multicast_hash(efx); + efx->type->push_multicast_hash(efx); efx->mac_op->reconfigure(efx); } mutex_unlock(&efx->mac_lock); @@ -696,8 +696,8 @@ static int efx_probe_port(struct efx_nic *efx) EFX_LOG(efx, "create port\n"); - /* Connect up MAC/PHY operations table and read MAC address */ - rc = falcon_probe_port(efx); + /* Connect up MAC/PHY operations table */ + rc = efx->type->probe_port(efx); if (rc) goto err; @@ -765,7 +765,7 @@ static void efx_start_port(struct efx_nic *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->type->push_multicast_hash(efx); efx->mac_op->reconfigure(efx); mutex_unlock(&efx->mac_lock); @@ -805,7 +805,7 @@ static void efx_remove_port(struct efx_nic *efx) { EFX_LOG(efx, "destroying port\n"); - falcon_remove_port(efx); + efx->type->remove_port(efx); } /************************************************************************** @@ -1042,7 +1042,7 @@ static int efx_probe_nic(struct efx_nic *efx) EFX_LOG(efx, "creating NIC\n"); /* Carry out hardware-type specific initialisation */ - rc = falcon_probe_nic(efx); + rc = efx->type->probe(efx); if (rc) return rc; @@ -1063,7 +1063,7 @@ static void efx_remove_nic(struct efx_nic *efx) EFX_LOG(efx, "destroying NIC\n"); efx_remove_interrupts(efx); - falcon_remove_nic(efx); + efx->type->remove(efx); } /************************************************************************** @@ -1145,12 +1145,12 @@ static void efx_start_all(struct efx_nic *efx) falcon_enable_interrupts(efx); - /* Start hardware monitor if we're in RUNNING */ - if (efx->state == STATE_RUNNING) + /* Start the hardware monitor (if there is one) if we're in RUNNING */ + if (efx->state == STATE_RUNNING && efx->type->monitor != NULL) queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); - falcon_start_nic_stats(efx); + efx->type->start_stats(efx); } /* Flush all delayed work. Should only be called when no more delayed work @@ -1186,7 +1186,7 @@ static void efx_stop_all(struct efx_nic *efx) if (!efx->port_enabled) return; - falcon_stop_nic_stats(efx); + efx->type->stop_stats(efx); /* Disable interrupts and wait for ISR to complete */ falcon_disable_interrupts(efx); @@ -1284,6 +1284,7 @@ static void efx_monitor(struct work_struct *data) EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", raw_smp_processor_id()); + BUG_ON(efx->type->monitor == NULL); /* If the mac_lock is already held then it is likely a port * reconfiguration is already in place, which will likely do @@ -1292,7 +1293,7 @@ static void efx_monitor(struct work_struct *data) goto out_requeue; if (!efx->port_enabled) goto out_unlock; - falcon_monitor(efx); + efx->type->monitor(efx); out_unlock: mutex_unlock(&efx->mac_lock); @@ -1430,7 +1431,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) struct net_device_stats *stats = &net_dev->stats; spin_lock_bh(&efx->stats_lock); - falcon_update_nic_stats(efx); + efx->type->update_stats(efx); spin_unlock_bh(&efx->stats_lock); stats->rx_packets = mac_stats->rx_packets; @@ -1695,6 +1696,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, efx_fini_channels(efx); if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) efx->phy_op->fini(efx); + efx->type->fini(efx); } /* This function will always ensure that the locks acquired in @@ -1709,7 +1711,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, EFX_ASSERT_RESET_SERIALISED(efx); - rc = falcon_init_nic(efx); + rc = efx->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); ok = false; @@ -1769,7 +1771,7 @@ static int efx_reset(struct efx_nic *efx) efx_reset_down(efx, method, &ecmd); - rc = falcon_reset_hw(efx, method); + rc = efx->type->reset(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); goto out_disable; @@ -2005,6 +2007,7 @@ static void efx_pci_remove_main(struct efx_nic *efx) falcon_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); + efx->type->fini(efx); efx_fini_napi(efx); efx_remove_all(efx); } @@ -2064,7 +2067,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) if (rc) goto fail2; - rc = falcon_init_nic(efx); + rc = efx->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); goto fail3; @@ -2088,6 +2091,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_fini_channels(efx); efx_fini_port(efx); fail4: + efx->type->fini(efx); fail3: efx_fini_napi(efx); fail2: diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index d3da360f09b..49e0aed920d 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -649,7 +649,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); efx_for_each_channel(channel, efx) - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); return 0; } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 040f553de66..f6d10213d0b 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1041,7 +1041,7 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota) return rx_packets; } -void falcon_set_int_moderation(struct efx_channel *channel) +static void falcon_push_irq_moderation(struct efx_channel *channel) { efx_dword_t timer_cmd; struct efx_nic *efx = channel->efx; @@ -1098,7 +1098,7 @@ void falcon_init_eventq(struct efx_channel *channel) efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, channel->channel); - falcon_set_int_moderation(channel); + falcon_push_irq_moderation(channel); } void falcon_fini_eventq(struct efx_channel *channel) @@ -1212,7 +1212,8 @@ int falcon_flush_queues(struct efx_nic *efx) struct efx_tx_queue *tx_queue; int i, tx_pending, rx_pending; - falcon_prepare_flush(efx); + /* If necessary prepare the hardware for flushing */ + efx->type->prepare_flush(efx); /* Flush all tx queues in parallel */ efx_for_each_tx_queue(tx_queue, efx) @@ -1825,6 +1826,16 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, ************************************************************************** */ +static void falcon_push_multicast_hash(struct efx_nic *efx) +{ + union efx_multicast_hash *mc_hash = &efx->multicast_hash; + + 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); +} + static int falcon_reset_macs(struct efx_nic *efx) { efx_oword_t reg; @@ -2240,7 +2251,7 @@ out: } /* This call is responsible for hooking in the MAC and PHY operations */ -int falcon_probe_port(struct efx_nic *efx) +static int falcon_probe_port(struct efx_nic *efx) { int rc; @@ -2299,29 +2310,11 @@ int falcon_probe_port(struct efx_nic *efx) return 0; } -void falcon_remove_port(struct efx_nic *efx) +static void falcon_remove_port(struct efx_nic *efx) { falcon_free_buffer(efx, &efx->stats_buffer); } -/************************************************************************** - * - * Multicast filtering - * - ************************************************************************** - */ - -void falcon_push_multicast_hash(struct efx_nic *efx) -{ - union efx_multicast_hash *mc_hash = &efx->multicast_hash; - - 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); -} - - /************************************************************************** * * Falcon test code @@ -2503,7 +2496,7 @@ fail: /* Resets NIC to known state. This routine must be called in process * context and is allowed to sleep. */ -int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) +static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) { struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t glb_ctl_reg_ker; @@ -2592,7 +2585,7 @@ fail5: return rc; } -void falcon_monitor(struct efx_nic *efx) +static void falcon_monitor(struct efx_nic *efx) { bool link_changed; int rc; @@ -2850,7 +2843,7 @@ static void falcon_probe_spi_devices(struct efx_nic *efx) large_eeprom_type); } -int falcon_probe_nic(struct efx_nic *efx) +static int falcon_probe_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data; struct falcon_board *board; @@ -3006,7 +2999,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) * defining the descriptor cache sizes and number of RSS channels. * It does not set up any buffers, descriptor rings or event queues. */ -int falcon_init_nic(struct efx_nic *efx) +static int falcon_init_nic(struct efx_nic *efx) { efx_oword_t temp; int rc; @@ -3139,7 +3132,7 @@ int falcon_init_nic(struct efx_nic *efx) return 0; } -void falcon_remove_nic(struct efx_nic *efx) +static void falcon_remove_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; struct falcon_board *board = falcon_board(efx); @@ -3168,7 +3161,7 @@ void falcon_remove_nic(struct efx_nic *efx) efx->nic_data = NULL; } -void falcon_update_nic_stats(struct efx_nic *efx) +static void falcon_update_nic_stats(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t cnt; @@ -3232,6 +3225,20 @@ void falcon_stop_nic_stats(struct efx_nic *efx) */ struct efx_nic_type falcon_a1_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_A1, @@ -3250,6 +3257,20 @@ struct efx_nic_type falcon_a1_nic_type = { }; struct efx_nic_type falcon_b0_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_B0, diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 81196a0fb50..3fe64849c98 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -129,10 +129,6 @@ extern void falcon_remove_eventq(struct efx_channel *channel); extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); extern void falcon_eventq_read_ack(struct efx_channel *channel); -/* Ports */ -extern int falcon_probe_port(struct efx_nic *efx); -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); @@ -146,23 +142,15 @@ extern void falcon_enable_interrupts(struct efx_nic *efx); extern void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic); extern void falcon_generate_interrupt(struct efx_nic *efx); -extern void falcon_set_int_moderation(struct efx_channel *channel); extern void falcon_disable_interrupts(struct efx_nic *efx); extern void falcon_fini_interrupt(struct efx_nic *efx); #define FALCON_IRQ_MOD_RESOLUTION 5 /* Global Resources */ -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); extern void falcon_stop_nic_stats(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 fddf8f5870c..32806f9a7e4 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -843,6 +843,21 @@ static inline const char *efx_dev_name(struct efx_nic *efx) /** * struct efx_nic_type - Efx device type definition + * @probe: Probe the controller + * @remove: Free resources allocated by probe() + * @init: Initialise the controller + * @fini: Shut down the controller + * @monitor: Periodic function for polling link state and hardware monitor + * @reset: Reset the controller hardware and possibly the PHY. This will + * be called while the controller is uninitialised. + * @probe_port: Probe the MAC and PHY + * @remove_port: Free resources allocated by probe_port() + * @prepare_flush: Prepare the hardware for flushing the DMA queues + * @update_stats: Update statistics not provided by event handling + * @start_stats: Start the regular fetching of statistics + * @stop_stats: Stop the regular fetching of statistics + * @push_irq_moderation: Apply interrupt moderation value + * @push_multicast_hash: Apply multicast hash table * @default_mac_ops: efx_mac_operations to set at startup * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size @@ -861,6 +876,20 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * @rx_dc_base: Base address in SRAM of RX queue descriptor caches */ struct efx_nic_type { + int (*probe)(struct efx_nic *efx); + void (*remove)(struct efx_nic *efx); + int (*init)(struct efx_nic *efx); + void (*fini)(struct efx_nic *efx); + void (*monitor)(struct efx_nic *efx); + int (*reset)(struct efx_nic *efx, enum reset_type method); + int (*probe_port)(struct efx_nic *efx); + void (*remove_port)(struct efx_nic *efx); + void (*prepare_flush)(struct efx_nic *efx); + void (*update_stats)(struct efx_nic *efx); + void (*start_stats)(struct efx_nic *efx); + void (*stop_stats)(struct efx_nic *efx); + void (*push_irq_moderation)(struct efx_channel *channel); + void (*push_multicast_hash)(struct efx_nic *efx); struct efx_mac_operations *default_mac_ops; int revision; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 74e84afd5b6..15d4d9c8136 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -719,7 +719,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, rc_test = rc; /* reset the chip to recover from the register test */ - rc_reset = falcon_reset_hw(efx, reset_method); + rc_reset = efx->type->reset(efx, reset_method); /* Ensure that the phy is powered and out of loopback * for the bist and loopback tests */ -- cgit v1.2.3-70-g09d2 From d3245b28ef2a45ec4e115062a38100bd06229289 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 03:42:41 +0000 Subject: sfc: Refactor link configuration Refactor PHY, MAC and NIC configuration operations so that the existing link configuration can be re-pushed with: efx->phy_op->reconfigure(efx); efx->mac_op->reconfigure(efx); and a new configuration with: efx->nic_op->reconfigure_port(efx); (plus locking and error-checking). We have not held the link settings in software (aside from flow control), and have relied on asking the hardware what they are. This is a problem because in some cases the hardware may no longer be in a state to tell us. In particular, if an entire multi-port board is reset through one port, the driver bindings to other ports have no chance to save settings before recovering. We only actually need to keep track of the autonegotiation settings, so add an ethtool advertising mask to struct efx_nic, initialise it in PHY init and update it as necessary. Remove now-unneeded uses of efx_phy_op::{get,set}_settings() and struct ethtool_cmd. Much of this was done by Steve Hodgson . Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 132 ++++++++++++++++++++++++---------------- drivers/net/sfc/efx.h | 12 ++-- drivers/net/sfc/ethtool.c | 61 +++++++++++++------ drivers/net/sfc/falcon.c | 98 ++++++++++++++++++----------- drivers/net/sfc/falcon.h | 3 - drivers/net/sfc/falcon_boards.c | 3 +- drivers/net/sfc/falcon_gmac.c | 4 +- drivers/net/sfc/falcon_xmac.c | 8 ++- drivers/net/sfc/mac.h | 1 + drivers/net/sfc/mdio_10g.c | 41 ++++++++----- drivers/net/sfc/mdio_10g.h | 3 + drivers/net/sfc/net_driver.h | 8 ++- drivers/net/sfc/qt202x_phy.c | 4 +- drivers/net/sfc/selftest.c | 11 ++-- drivers/net/sfc/tenxpress.c | 66 ++++++++------------ 15 files changed, 273 insertions(+), 182 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 73ab246d9f2..4210121eeff 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -620,16 +620,49 @@ void efx_link_status_changed(struct efx_nic *efx) } +void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) +{ + efx->link_advertising = advertising; + if (advertising) { + if (advertising & ADVERTISED_Pause) + efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX); + else + efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); + if (advertising & ADVERTISED_Asym_Pause) + efx->wanted_fc ^= EFX_FC_TX; + } +} + +void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) +{ + efx->wanted_fc = wanted_fc; + if (efx->link_advertising) { + if (wanted_fc & EFX_FC_RX) + efx->link_advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + else + efx->link_advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + if (wanted_fc & EFX_FC_TX) + efx->link_advertising ^= ADVERTISED_Asym_Pause; + } +} + static void efx_fini_port(struct efx_nic *efx); -/* This call reinitialises the MAC to pick up new PHY settings. The - * caller must hold the mac_lock */ -void __efx_reconfigure_port(struct efx_nic *efx) +/* Push loopback/power/transmit disable settings to the PHY, and reconfigure + * the MAC appropriately. All other PHY configuration changes are pushed + * through phy_op->set_settings(), and pushed asynchronously to the MAC + * through efx_monitor(). + * + * Callers must hold the mac_lock + */ +int __efx_reconfigure_port(struct efx_nic *efx) { - WARN_ON(!mutex_is_locked(&efx->mac_lock)); + enum efx_phy_mode phy_mode; + int rc; - EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n", - raw_smp_processor_id()); + WARN_ON(!mutex_is_locked(&efx->mac_lock)); /* Serialise the promiscuous flag with efx_set_multicast_list. */ if (efx_dev_registered(efx)) { @@ -637,42 +670,34 @@ void __efx_reconfigure_port(struct efx_nic *efx) netif_addr_unlock_bh(efx->net_dev); } - efx->type->stop_stats(efx); - falcon_deconfigure_mac_wrapper(efx); - - /* Reconfigure the PHY, disabling transmit in mac level loopback. */ + /* Disable PHY transmit in mac level loopbacks */ + phy_mode = efx->phy_mode; if (LOOPBACK_INTERNAL(efx)) efx->phy_mode |= PHY_MODE_TX_DISABLED; else efx->phy_mode &= ~PHY_MODE_TX_DISABLED; - efx->phy_op->reconfigure(efx); - - if (falcon_switch_mac(efx)) - goto fail; - efx->mac_op->reconfigure(efx); + rc = efx->type->reconfigure_port(efx); - efx->type->start_stats(efx); - - /* Inform kernel of loss/gain of carrier */ - efx_link_status_changed(efx); - return; + if (rc) + efx->phy_mode = phy_mode; -fail: - EFX_ERR(efx, "failed to reconfigure MAC\n"); - efx->port_enabled = false; - efx_fini_port(efx); + return rc; } /* Reinitialise the MAC to pick up new PHY settings, even if the port is * disabled. */ -void efx_reconfigure_port(struct efx_nic *efx) +int efx_reconfigure_port(struct efx_nic *efx) { + int rc; + EFX_ASSERT_RESET_SERIALISED(efx); mutex_lock(&efx->mac_lock); - __efx_reconfigure_port(efx); + rc = __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); + + return rc; } /* Asynchronous work item for changing MAC promiscuity and multicast @@ -737,14 +762,18 @@ static int efx_init_port(struct efx_nic *efx) rc = efx->phy_op->init(efx); if (rc) goto fail1; - efx->phy_op->reconfigure(efx); - rc = falcon_switch_mac(efx); - if (rc) - goto fail2; - efx->mac_op->reconfigure(efx); efx->port_initialized = true; + /* Reconfigure the MAC before creating dma queues (required for + * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ + efx->mac_op->reconfigure(efx); + + /* Ensure the PHY advertises the correct flow control settings */ + rc = efx->phy_op->reconfigure(efx); + if (rc) + goto fail2; + mutex_unlock(&efx->mac_lock); return 0; @@ -1209,12 +1238,6 @@ static void efx_stop_all(struct efx_nic *efx) /* Flush efx_mac_work(), refill_workqueue, monitor_work */ efx_flush_all(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); - msleep(10); /* Let the Rx FIFO drain */ - falcon_drain_tx_fifo(efx); - /* Stop the kernel transmit interface late, so the watchdog * timer isn't ticking over the flush */ if (efx_dev_registered(efx)) { @@ -1491,7 +1514,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) EFX_LOG(efx, "changing MTU to %d\n", new_mtu); efx_fini_channels(efx); + + mutex_lock(&efx->mac_lock); + /* Reconfigure the MAC before enabling the dma queues so that + * the RX buffers don't overflow */ net_dev->mtu = new_mtu; + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + efx_init_channels(efx); efx_start_all(efx); @@ -1515,7 +1545,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); /* Reconfigure the MAC */ - efx_reconfigure_port(efx); + mutex_lock(&efx->mac_lock); + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); return 0; } @@ -1682,8 +1714,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) /* Tears down the entire software state and most of the hardware state * before reset. */ -void efx_reset_down(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd) +void efx_reset_down(struct efx_nic *efx, enum reset_type method) { EFX_ASSERT_RESET_SERIALISED(efx); @@ -1691,8 +1722,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, mutex_lock(&efx->mac_lock); mutex_lock(&efx->spi_lock); - efx->phy_op->get_settings(efx, ecmd); - efx_fini_channels(efx); if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) efx->phy_op->fini(efx); @@ -1704,8 +1733,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, * 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. */ -int efx_reset_up(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd, bool ok) +int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) { int rc; @@ -1722,16 +1750,17 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, rc = efx->phy_op->init(efx); if (rc) ok = false; + if (efx->phy_op->reconfigure(efx)) + EFX_ERR(efx, "could not restore PHY settings\n"); } if (!ok) efx->port_initialized = false; } if (ok) { - efx_init_channels(efx); + efx->mac_op->reconfigure(efx); - if (efx->phy_op->set_settings(efx, ecmd)) - EFX_ERR(efx, "could not restore PHY settings\n"); + efx_init_channels(efx); } mutex_unlock(&efx->spi_lock); @@ -1753,7 +1782,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, */ static int efx_reset(struct efx_nic *efx) { - struct ethtool_cmd ecmd; enum reset_type method = efx->reset_pending; int rc = 0; @@ -1769,7 +1797,7 @@ static int efx_reset(struct efx_nic *efx) EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); - efx_reset_down(efx, method, &ecmd); + efx_reset_down(efx, method); rc = efx->type->reset(efx, method); if (rc) { @@ -1788,10 +1816,10 @@ static int efx_reset(struct efx_nic *efx) /* Leave device stopped if necessary */ if (method == RESET_TYPE_DISABLE) { - efx_reset_up(efx, method, &ecmd, false); + efx_reset_up(efx, method, false); rc = -EIO; } else { - rc = efx_reset_up(efx, method, &ecmd, true); + rc = efx_reset_up(efx, method, true); } out_disable: @@ -1895,7 +1923,7 @@ bool efx_port_dummy_op_poll(struct efx_nic *efx) static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, - .reconfigure = efx_port_dummy_op_void, + .reconfigure = efx_port_dummy_op_int, .poll = efx_port_dummy_op_poll, .fini = efx_port_dummy_op_void, }; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 15edda2a224..c7850032158 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -60,8 +60,8 @@ extern void efx_process_channel_now(struct efx_channel *channel); #define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1) /* Ports */ -extern void efx_reconfigure_port(struct efx_nic *efx); -extern void __efx_reconfigure_port(struct efx_nic *efx); +extern int efx_reconfigure_port(struct efx_nic *efx); +extern int __efx_reconfigure_port(struct efx_nic *efx); /* Ethtool support */ extern int efx_ethtool_get_settings(struct net_device *net_dev, @@ -71,10 +71,8 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev, extern const struct ethtool_ops efx_ethtool_ops; /* Reset handling */ -extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd); -extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd, bool ok); +extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); +extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); @@ -115,5 +113,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) } extern void efx_link_status_changed(struct efx_nic *efx); +extern void efx_link_set_advertising(struct efx_nic *efx, u32); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 49e0aed920d..d95d0fa399f 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -10,7 +10,6 @@ #include #include -#include #include #include "net_driver.h" #include "workarounds.h" @@ -191,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); + struct efx_link_state *link_state = &efx->link_state; mutex_lock(&efx->mac_lock); efx->phy_op->get_settings(efx, ecmd); @@ -198,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev, /* Falcon GMAC does not support 1000Mbps HD */ ecmd->supported &= ~SUPPORTED_1000baseT_Half; + /* Both MACs support pause frames (bidirectional and respond-only) */ + ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + + if (LOOPBACK_INTERNAL(efx)) { + ecmd->speed = link_state->speed; + ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; + } return 0; } @@ -219,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev, mutex_lock(&efx->mac_lock); rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); - if (!rc) - efx_reconfigure_port(efx); - return rc; } @@ -658,8 +662,12 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type wanted_fc; + enum efx_fc_type wanted_fc, old_fc; + u32 old_adv; bool reset; + int rc = 0; + + mutex_lock(&efx->mac_lock); wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | (pause->tx_pause ? EFX_FC_TX : 0) | @@ -667,14 +675,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); - return -EINVAL; + rc = -EINVAL; + goto out; } - if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && - (wanted_fc & EFX_FC_AUTO)) { - EFX_LOG(efx, "PHY does not support flow control " - "autonegotiation\n"); - return -EINVAL; + if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) { + EFX_LOG(efx, "Autonegotiation is disabled\n"); + rc = -EINVAL; + goto out; } /* TX flow control may automatically turn itself off if the @@ -686,25 +694,38 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, if (EFX_WORKAROUND_11482(efx) && reset) { if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { /* Recover by resetting the EM block */ - if (efx->link_state.up) - falcon_drain_tx_fifo(efx); + falcon_stop_nic_stats(efx); + falcon_drain_tx_fifo(efx); + efx->mac_op->reconfigure(efx); + falcon_start_nic_stats(efx); } else { /* Schedule a reset to recover */ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); } } - /* Try to push the pause parameters */ - mutex_lock(&efx->mac_lock); + old_adv = efx->link_advertising; + old_fc = efx->wanted_fc; + efx_link_set_wanted_fc(efx, wanted_fc); + if (efx->link_advertising != old_adv || + (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { + rc = efx->phy_op->reconfigure(efx); + if (rc) { + EFX_ERR(efx, "Unable to advertise requested flow " + "control setting\n"); + goto out; + } + } - efx->wanted_fc = wanted_fc; - if (efx->phy_op->mmds & MDIO_DEVS_AN) - mdio45_ethtool_spauseparam_an(&efx->mdio, pause); - __efx_reconfigure_port(efx); + /* Reconfigure the MAC. The PHY *may* generate a link state change event + * if the user just changed the advertised capabilities, but there's no + * harm doing this twice */ + efx->mac_op->reconfigure(efx); +out: mutex_unlock(&efx->mac_lock); - return 0; + return rc; } static void efx_ethtool_get_pauseparam(struct net_device *net_dev, diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index f6d10213d0b..3466616c01c 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1193,6 +1193,8 @@ static void falcon_poll_flush_events(struct efx_nic *efx) channel->eventq_read_ptr = read_ptr; } +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); + static void falcon_prepare_flush(struct efx_nic *efx) { falcon_deconfigure_mac_wrapper(efx); @@ -1836,9 +1838,10 @@ static void falcon_push_multicast_hash(struct efx_nic *efx) efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); } -static int falcon_reset_macs(struct efx_nic *efx) +static void falcon_reset_macs(struct efx_nic *efx) { - efx_oword_t reg; + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg, mac_ctrl; int count; if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { @@ -1853,7 +1856,7 @@ static int falcon_reset_macs(struct efx_nic *efx) EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0); efx_writeo(efx, ®, FR_AB_GM_CFG1); udelay(1000); - return 0; + return; } else { EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); @@ -1862,22 +1865,20 @@ static int falcon_reset_macs(struct efx_nic *efx) efx_reado(efx, ®, FR_AB_XM_GLB_CFG); if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == 0) - return 0; + return; udelay(10); } EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); - return -ETIMEDOUT; } } - /* MAC stats will fail whilst the TX fifo is draining. Serialise - * the drain sequence with the statistics fetch */ - falcon_stop_nic_stats(efx); + /* Mac stats will fail whist the TX fifo is draining */ + WARN_ON(nic_data->stats_disable_count == 0); - efx_reado(efx, ®, FR_AB_MAC_CTRL); - EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1); - efx_writeo(efx, ®, FR_AB_MAC_CTRL); + efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); + EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); efx_reado(efx, ®, FR_AB_GLB_CTL); EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); @@ -1903,14 +1904,9 @@ static int falcon_reset_macs(struct efx_nic *efx) udelay(10); } - /* 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; + /* Ensure the correct MAC is selected before statistics + * are re-enabled by the caller */ + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); } void falcon_drain_tx_fifo(struct efx_nic *efx) @@ -1929,7 +1925,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx) falcon_reset_macs(efx); } -void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) { efx_oword_t reg; @@ -1941,8 +1937,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); efx_writeo(efx, ®, FR_AZ_RX_CFG); - if (!efx->link_state.up) - falcon_drain_tx_fifo(efx); + /* Isolate TX -> MAC */ + falcon_drain_tx_fifo(efx); } void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) @@ -2044,6 +2040,8 @@ static void falcon_stats_timer_func(unsigned long context) spin_unlock(&efx->stats_lock); } +static void falcon_switch_mac(struct efx_nic *efx); + static bool falcon_loopback_link_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; @@ -2063,6 +2061,38 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx) return !efx_link_state_equal(&efx->link_state, &old_state); } +static int falcon_reconfigure_port(struct efx_nic *efx) +{ + int rc; + + WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0); + + /* Poll the PHY link state *before* reconfiguring it. This means we + * will pick up the correct speed (in loopback) to select the correct + * MAC. + */ + if (LOOPBACK_INTERNAL(efx)) + falcon_loopback_link_poll(efx); + else + efx->phy_op->poll(efx); + + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_switch_mac(efx); + + efx->phy_op->reconfigure(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); + + falcon_start_nic_stats(efx); + + /* Synchronise efx->link_state with the kernel */ + efx_link_status_changed(efx); + + return 0; +} + /************************************************************************** * * PHY access via GMII @@ -2215,17 +2245,15 @@ static void falcon_clock_mac(struct efx_nic *efx) } } -int falcon_switch_mac(struct efx_nic *efx) +static void 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 */ - falcon_stop_nic_stats(efx); WARN_ON(!mutex_is_locked(&efx->mac_lock)); + WARN_ON(nic_data->stats_disable_count == 0); + efx->mac_op = (EFX_IS10G(efx) ? &falcon_xmac_operations : &falcon_gmac_operations); @@ -2236,18 +2264,14 @@ int falcon_switch_mac(struct efx_nic *efx) nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; if (old_mac_op == efx->mac_op) - goto out; + return; 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->xmac_poll_required = false; - - rc = falcon_reset_macs(efx); -out: - falcon_start_nic_stats(efx); - return rc; + falcon_reset_macs(efx); } /* This call is responsible for hooking in the MAC and PHY operations */ @@ -2597,7 +2621,8 @@ static void falcon_monitor(struct efx_nic *efx) EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", (rc == -ERANGE) ? "reported fault" : "failed"); efx->phy_mode |= PHY_MODE_LOW_POWER; - __efx_reconfigure_port(efx); + rc = __efx_reconfigure_port(efx); + WARN_ON(rc); } if (LOOPBACK_INTERNAL(efx)) @@ -2610,7 +2635,8 @@ static void falcon_monitor(struct efx_nic *efx) falcon_deconfigure_mac_wrapper(efx); falcon_switch_mac(efx); - efx->mac_op->reconfigure(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); falcon_start_nic_stats(efx); @@ -3239,6 +3265,7 @@ struct efx_nic_type falcon_a1_nic_type = { .stop_stats = falcon_stop_nic_stats, .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_A1, @@ -3271,6 +3298,7 @@ struct efx_nic_type falcon_b0_nic_type = { .stop_stats = falcon_stop_nic_stats, .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_B0, diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 3fe64849c98..560a3f9895a 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -130,10 +130,7 @@ extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); extern void falcon_eventq_read_ack(struct efx_channel *channel); /* MAC/PHY */ -extern int falcon_switch_mac(struct efx_nic *efx); -extern bool falcon_xaui_link_ok(struct efx_nic *efx); 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); /* Interrupts and test events */ diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index da750959c61..b92decc9521 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -352,7 +352,8 @@ static ssize_t set_phy_flash_cfg(struct device *dev, err = sfe4001_poweron(efx); else err = sfn4111t_reset(efx); - efx_reconfigure_port(efx); + if (!err) + err = efx_reconfigure_port(efx); if (!(new_mode & PHY_MODE_SPECIAL)) falcon_start_nic_stats(efx); } diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index 66d499cc23f..19dd3ac3d1c 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c @@ -22,7 +22,7 @@ * *************************************************************************/ -static void falcon_reconfigure_gmac(struct efx_nic *efx) +static int falcon_reconfigure_gmac(struct efx_nic *efx) { struct efx_link_state *link_state = &efx->link_state; bool loopback, tx_fc, rx_fc, bytemode; @@ -123,6 +123,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) udelay(10); falcon_reconfigure_mac_wrapper(efx); + + return 0; } static void falcon_update_stats_gmac(struct efx_nic *efx) diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 60dc0975cfa..898afc1b5ef 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -112,7 +112,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) } /* Get status of XAUI link */ -bool falcon_xaui_link_ok(struct efx_nic *efx) +static bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; bool align_done, link_ok = false; @@ -143,7 +143,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) return link_ok; } -static void falcon_reconfigure_xmac_core(struct efx_nic *efx) +void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; @@ -275,7 +275,7 @@ 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) +static int falcon_reconfigure_xmac(struct efx_nic *efx) { falcon_mask_status_intr(efx, false); @@ -286,6 +286,8 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx) efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); falcon_mask_status_intr(efx, true); + + return 0; } static void falcon_update_stats_xmac(struct efx_nic *efx) diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index 4e7074278fe..d2af50f1747 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -15,5 +15,6 @@ extern struct efx_mac_operations falcon_gmac_operations; extern struct efx_mac_operations falcon_xmac_operations; +extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); #endif diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 231e580acc9..1f62a5c002f 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -248,8 +248,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { struct ethtool_cmd prev; - bool xnp; - int reg; efx->phy_op->get_settings(efx, &prev); @@ -269,30 +267,47 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) return -EINVAL; - xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full - || EFX_WORKAROUND_13204(efx)); + efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); + efx_mdio_an_reconfigure(efx); + return 0; +} + +/** + * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation + * @efx: Efx NIC + */ +void efx_mdio_an_reconfigure(struct efx_nic *efx) +{ + bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full + || EFX_WORKAROUND_13204(efx)); + int reg; + + WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); /* Set up the base page */ reg = ADVERTISE_CSMA; - if (ecmd->advertising & ADVERTISED_10baseT_Half) + if (efx->link_advertising & ADVERTISED_10baseT_Half) reg |= ADVERTISE_10HALF; - if (ecmd->advertising & ADVERTISED_10baseT_Full) + if (efx->link_advertising & ADVERTISED_10baseT_Full) reg |= ADVERTISE_10FULL; - if (ecmd->advertising & ADVERTISED_100baseT_Half) + if (efx->link_advertising & ADVERTISED_100baseT_Half) reg |= ADVERTISE_100HALF; - if (ecmd->advertising & ADVERTISED_100baseT_Full) + if (efx->link_advertising & ADVERTISED_100baseT_Full) reg |= ADVERTISE_100FULL; if (xnp) reg |= ADVERTISE_RESV; - else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full)) + else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) reg |= ADVERTISE_NPAGE; - reg |= mii_advertise_flowctrl(efx->wanted_fc); + if (efx->link_advertising & ADVERTISED_Pause) + reg |= ADVERTISE_PAUSE_CAP; + if (efx->link_advertising & ADVERTISED_Asym_Pause) + reg |= ADVERTISE_PAUSE_ASYM; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Set up the (extended) next page if necessary */ if (efx->phy_op->set_npage_adv) - efx->phy_op->set_npage_adv(efx, ecmd->advertising); + efx->phy_op->set_npage_adv(efx, efx->link_advertising); /* Enable and restart AN */ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); @@ -305,8 +320,6 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) else reg &= ~MDIO_AN_CTRL1_XNP; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); - - return 0; } enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 75b37f10123..dbc8e7de292 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -86,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, /* Set (some of) the PHY settings over MDIO */ extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Push advertising flags and restart autonegotiation */ +extern void efx_mdio_an_reconfigure(struct efx_nic *efx); + /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 32806f9a7e4..f63a05c4e38 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -517,7 +517,7 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left, * @check_fault: Check fault state. True if fault present. */ struct efx_mac_operations { - void (*reconfigure) (struct efx_nic *efx); + int (*reconfigure) (struct efx_nic *efx); void (*update_stats) (struct efx_nic *efx); bool (*check_fault)(struct efx_nic *efx); }; @@ -544,7 +544,7 @@ struct efx_phy_operations { enum efx_mac_type macs; int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); - void (*reconfigure) (struct efx_nic *efx); + int (*reconfigure) (struct efx_nic *efx); bool (*poll) (struct efx_nic *efx); void (*get_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); @@ -730,6 +730,7 @@ union efx_multicast_hash { * @mdio: PHY MDIO interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @xmac_poll_required: XMAC link state needs polling + * @link_advertising: Autonegotiation advertising flags * @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. @@ -813,6 +814,7 @@ struct efx_nic { enum efx_phy_mode phy_mode; bool xmac_poll_required; + u32 link_advertising; struct efx_link_state link_state; unsigned int n_link_state_changes; @@ -858,6 +860,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * @stop_stats: Stop the regular fetching of statistics * @push_irq_moderation: Apply interrupt moderation value * @push_multicast_hash: Apply multicast hash table + * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY * @default_mac_ops: efx_mac_operations to set at startup * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size @@ -890,6 +893,7 @@ struct efx_nic_type { void (*stop_stats)(struct efx_nic *efx); void (*push_irq_moderation)(struct efx_channel *channel); void (*push_multicast_hash)(struct efx_nic *efx); + int (*reconfigure_port)(struct efx_nic *efx); struct efx_mac_operations *default_mac_ops; int revision; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 3d7370e3978..4c38516a552 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -178,7 +178,7 @@ static bool qt202x_phy_poll(struct efx_nic *efx) return efx->link_state.up != was_up; } -static void qt202x_phy_reconfigure(struct efx_nic *efx) +static int qt202x_phy_reconfigure(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; @@ -207,6 +207,8 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx) efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; + + return 0; } static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 15d4d9c8136..dddeb9dfb37 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -659,7 +659,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, enum efx_loopback_mode loopback_mode = efx->loopback_mode; int phy_mode = efx->phy_mode; enum reset_type reset_method = RESET_TYPE_INVISIBLE; - struct ethtool_cmd ecmd; struct efx_channel *channel; int rc_test = 0, rc_reset = 0, rc; @@ -712,7 +711,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, mutex_unlock(&efx->mac_lock); /* free up all consumers of SRAM (including all the queues) */ - efx_reset_down(efx, reset_method, &ecmd); + efx_reset_down(efx, reset_method); rc = efx_test_chip(efx, tests); if (rc && !rc_test) @@ -726,7 +725,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); + rc = efx_reset_up(efx, reset_method, rc_reset == 0); if (rc && !rc_reset) rc_reset = rc; @@ -745,10 +744,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, rc_test = rc; /* restore the PHY to the previous state */ - efx->loopback_mode = loopback_mode; + mutex_lock(&efx->mac_lock); efx->phy_mode = phy_mode; efx->port_inhibited = false; - efx_ethtool_set_settings(efx->net_dev, &ecmd); + efx->loopback_mode = loopback_mode; + __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); return rc_test; } diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 1bd79650a00..c30185393cd 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -199,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev, const char *buf, size_t count) { struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + int rc; rtnl_lock(); efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, MDIO_PMA_10GBT_TXPWR_SHORT, count != 0 && *buf != '0'); - efx_reconfigure_port(efx); + rc = efx_reconfigure_port(efx); rtnl_unlock(); - return count; + return rc < 0 ? rc : (ssize_t)count; } static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, @@ -300,7 +301,6 @@ static int tenxpress_init(struct efx_nic *efx) static int tenxpress_phy_init(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data; - u16 old_adv, adv; int rc = 0; falcon_board(efx)->type->init_phy(efx); @@ -335,14 +335,14 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (rc < 0) goto fail; - /* Set pause advertising */ - old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) | - mii_advertise_flowctrl(efx->wanted_fc)); - if (adv != old_adv) { - efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv); - mdio45_nway_restart(&efx->mdio); - } + /* Initialise advertising flags */ + efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full); + if (efx->phy_type != PHY_TYPE_SFX7101) + efx->link_advertising |= (ADVERTISED_1000baseT_Full | + ADVERTISED_100baseT_Full); + efx_link_set_wanted_fc(efx, efx->wanted_fc); + efx_mdio_an_reconfigure(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, @@ -500,49 +500,41 @@ static void tenxpress_low_power(struct efx_nic *efx) !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } -static void tenxpress_phy_reconfigure(struct efx_nic *efx) +static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; - return; + return 0; } - tenxpress_low_power(efx); - phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { - int rc; - - efx->phy_op->get_settings(efx, &ecmd); + tenxpress_special_reset(efx); - if (loop_reset || phy_mode_change) { - tenxpress_special_reset(efx); - - /* Reset XAUI if we were in 10G, and are staying - * in 10G. If we're moving into and out of 10G - * then xaui will be reset anyway */ - if (EFX_IS10G(efx)) - falcon_reset_xaui(efx); - } - - rc = efx->phy_op->set_settings(efx, &ecmd); - WARN_ON(rc); + /* Reset XAUI if we were in 10G, and are staying + * in 10G. If we're moving into and out of 10G + * then xaui will be reset anyway */ + if (EFX_IS10G(efx)) + falcon_reset_xaui(efx); } + tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); + efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; + + return 0; } static void @@ -646,6 +638,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) /* BIST is automatically run after a special software reset */ rc = tenxpress_special_reset(efx); results[0] = rc ? -1 : 1; + + efx_mdio_an_reconfigure(efx); + return rc; } @@ -663,12 +658,8 @@ static const char *const sft9001_test_names[] = { static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { - struct ethtool_cmd ecmd; int rc = 0, rc2, i, ctrl_reg, res_reg; - if (flags & ETH_TEST_FL_OFFLINE) - efx->phy_op->get_settings(efx, &ecmd); - /* Initialise cable diagnostic results to unknown failure */ for (i = 1; i < 9; ++i) results[i] = -1; @@ -720,9 +711,7 @@ out: if (!rc) rc = rc2; - rc2 = efx->phy_op->set_settings(efx, &ecmd); - if (!rc) - rc = rc2; + efx_mdio_an_reconfigure(efx); } return rc; @@ -753,7 +742,6 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); -- cgit v1.2.3-70-g09d2 From 78c1f0a06551f6ff61bfd7c1a9302115a8135a62 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Sun, 29 Nov 2009 03:43:00 +0000 Subject: sfc: Generalise link state monitoring Use the efx_nic_type::monitor operation or event handling as appropriate. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 16 ++++++++-- drivers/net/sfc/selftest.c | 79 +++++++++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 34 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4210121eeff..14ef27fa841 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1174,10 +1174,18 @@ static void efx_start_all(struct efx_nic *efx) falcon_enable_interrupts(efx); - /* Start the hardware monitor (if there is one) if we're in RUNNING */ - if (efx->state == STATE_RUNNING && efx->type->monitor != NULL) + /* Start the hardware monitor if there is one. Otherwise (we're link + * event driven), we have to poll the PHY because after an event queue + * flush, we could have a missed a link state change */ + if (efx->type->monitor != NULL) { queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); + } else { + mutex_lock(&efx->mac_lock); + if (efx->phy_op->poll(efx)) + efx_link_status_changed(efx); + mutex_unlock(&efx->mac_lock); + } efx->type->start_stats(efx); } @@ -1421,6 +1429,10 @@ static int efx_net_open(struct net_device *net_dev) if (efx->phy_mode & PHY_MODE_SPECIAL) return -EBUSY; + /* Notify the kernel of the link state polled during driver load, + * before the monitor starts running */ + efx_link_status_changed(efx); + efx_start_all(efx); return 0; } diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index dddeb9dfb37..f45bf744215 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } +/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but + * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it + * to delay and retry. Therefore, it's safer to just poll directly. Wait + * for link up and any faults to dissipate. */ +static int efx_wait_for_link(struct efx_nic *efx) +{ + struct efx_link_state *link_state = &efx->link_state; + int count; + bool link_up; + + for (count = 0; count < 40; count++) { + schedule_timeout_uninterruptible(HZ / 10); + + if (efx->type->monitor != NULL) { + mutex_lock(&efx->mac_lock); + efx->type->monitor(efx); + mutex_unlock(&efx->mac_lock); + } else { + struct efx_channel *channel = &efx->channel[0]; + if (channel->work_pending) + efx_process_channel_now(channel); + } + + mutex_lock(&efx->mac_lock); + link_up = link_state->up; + if (link_up) + link_up = !efx->mac_op->check_fault(efx); + mutex_unlock(&efx->mac_lock); + + if (link_up) + return 0; + } + + return -ETIMEDOUT; +} + static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { enum efx_loopback_mode mode; struct efx_loopback_state *state; struct efx_tx_queue *tx_queue; - bool link_up; - int count, rc = 0; + int rc = 0; /* Set the port loopback_selftest member. From this point on * all received packets will be dropped. Mark the state as @@ -589,43 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, /* Move the port into the specified loopback mode. */ state->flush = true; + mutex_lock(&efx->mac_lock); efx->loopback_mode = mode; - efx_reconfigure_port(efx); - - /* Wait for the PHY to signal the link is up. Interrupts - * are enabled for PHY's using LASI, otherwise we poll() - * quickly */ - count = 0; - do { - struct efx_channel *channel = &efx->channel[0]; - - efx->phy_op->poll(efx); - schedule_timeout_uninterruptible(HZ / 10); - if (channel->work_pending) - efx_process_channel_now(channel); - /* Wait for PHY events to be processed */ - flush_workqueue(efx->workqueue); - rmb(); - - /* We need both the PHY and MAC-PHY links to be OK */ - link_up = efx->link_state.up; - if (link_up) - link_up = !efx->mac_op->check_fault(efx); - - } while ((++count < 20) && !link_up); + rc = __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); + if (rc) { + EFX_ERR(efx, "unable to move into %s loopback\n", + LOOPBACK_MODE(efx)); + goto out; + } - /* The link should now be up. If it isn't, there is no point - * in attempting a loopback test */ - if (!link_up) { + rc = efx_wait_for_link(efx); + if (rc) { EFX_ERR(efx, "loopback %s never came up\n", LOOPBACK_MODE(efx)); - rc = -EIO; goto out; } - EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", - LOOPBACK_MODE(efx), count); - /* Test every TX queue */ efx_for_each_tx_queue(tx_queue, efx) { state->offload_csum = (tx_queue->queue == -- cgit v1.2.3-70-g09d2 From 89c758fa47b54d8ce10d2b39ed09de6da0ba4324 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 03:43:07 +0000 Subject: sfc: Add power-management and wake-on-LAN support Wake-on-LAN is a stub for Falcon, but will be implemented fully for new NICs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/ethtool.c | 17 ++++++++ drivers/net/sfc/falcon.c | 27 +++++++++++++ drivers/net/sfc/net_driver.h | 6 +++ 4 files changed, 146 insertions(+) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 14ef27fa841..b016719d8f6 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2243,11 +2243,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, return rc; } +static int efx_pm_freeze(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_FINI; + + netif_device_detach(efx->net_dev); + + efx_stop_all(efx); + efx_fini_channels(efx); + + return 0; +} + +static int efx_pm_thaw(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_INIT; + + efx_init_channels(efx); + + mutex_lock(&efx->mac_lock); + efx->phy_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + netif_device_attach(efx->net_dev); + + efx->state = STATE_RUNNING; + + efx->type->resume_wol(efx); + + return 0; +} + +static int efx_pm_poweroff(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + + efx->type->fini(efx); + + efx->reset_pending = RESET_TYPE_NONE; + + pci_save_state(pci_dev); + return pci_set_power_state(pci_dev, PCI_D3hot); +} + +/* Used for both resume and restore */ +static int efx_pm_resume(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + int rc; + + rc = pci_set_power_state(pci_dev, PCI_D0); + if (rc) + return rc; + pci_restore_state(pci_dev); + rc = pci_enable_device(pci_dev); + if (rc) + return rc; + pci_set_master(efx->pci_dev); + rc = efx->type->reset(efx, RESET_TYPE_ALL); + if (rc) + return rc; + rc = efx->type->init(efx); + if (rc) + return rc; + efx_pm_thaw(dev); + return 0; +} + +static int efx_pm_suspend(struct device *dev) +{ + int rc; + + efx_pm_freeze(dev); + rc = efx_pm_poweroff(dev); + if (rc) + efx_pm_resume(dev); + return rc; +} + +static struct dev_pm_ops efx_pm_ops = { + .suspend = efx_pm_suspend, + .resume = efx_pm_resume, + .freeze = efx_pm_freeze, + .thaw = efx_pm_thaw, + .poweroff = efx_pm_poweroff, + .restore = efx_pm_resume, +}; + static struct pci_driver efx_pci_driver = { .name = EFX_DRIVER_NAME, .id_table = efx_pci_table, .probe = efx_pci_probe, .remove = efx_pci_remove, + .driver.pm = &efx_pm_ops, }; /************************************************************************** diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index d95d0fa399f..b4c6ea1b9c0 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -739,6 +739,21 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, } +static void efx_ethtool_get_wol(struct net_device *net_dev, + struct ethtool_wolinfo *wol) +{ + struct efx_nic *efx = netdev_priv(net_dev); + return efx->type->get_wol(efx, wol); +} + + +static int efx_ethtool_set_wol(struct net_device *net_dev, + struct ethtool_wolinfo *wol) +{ + struct efx_nic *efx = netdev_priv(net_dev); + return efx->type->set_wol(efx, wol->wolopts); +} + const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, @@ -767,4 +782,6 @@ const struct ethtool_ops efx_ethtool_ops = { .get_strings = efx_ethtool_get_strings, .phys_id = efx_ethtool_phys_id, .get_ethtool_stats = efx_ethtool_get_stats, + .get_wol = efx_ethtool_get_wol, + .set_wol = efx_ethtool_set_wol, }; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 3466616c01c..8f2c5830553 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -3243,6 +3243,27 @@ void falcon_stop_nic_stats(struct efx_nic *efx) spin_unlock_bh(&efx->stats_lock); } +/************************************************************************** + * + * Wake on LAN + * + ************************************************************************** + */ + +static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int falcon_set_wol(struct efx_nic *efx, u32 type) +{ + if (type != 0) + return -EINVAL; + return 0; +} + /************************************************************************** * * Revision-dependent attributes used by efx.c @@ -3266,6 +3287,9 @@ struct efx_nic_type falcon_a1_nic_type = { .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_A1, @@ -3299,6 +3323,9 @@ struct efx_nic_type falcon_b0_nic_type = { .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_B0, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index f63a05c4e38..a9fde82aeea 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -861,6 +861,9 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * @push_irq_moderation: Apply interrupt moderation value * @push_multicast_hash: Apply multicast hash table * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY + * @get_wol: Get WoL configuration from driver state + * @set_wol: Push WoL configuration to the NIC + * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) * @default_mac_ops: efx_mac_operations to set at startup * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size @@ -894,6 +897,9 @@ struct efx_nic_type { void (*push_irq_moderation)(struct efx_channel *channel); void (*push_multicast_hash)(struct efx_nic *efx); int (*reconfigure_port)(struct efx_nic *efx); + void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); + int (*set_wol)(struct efx_nic *efx, u32 type); + void (*resume_wol)(struct efx_nic *efx); struct efx_mac_operations *default_mac_ops; int revision; -- cgit v1.2.3-70-g09d2 From eb9f6744cbfa97674c13263802259b5aa0034594 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 03:43:15 +0000 Subject: sfc: Implement ethtool reset operation Refactor efx_reset_down() and efx_reset_up() accordingly. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 98 ++++++++++++++++++++++---------------------- drivers/net/sfc/efx.h | 1 + drivers/net/sfc/ethtool.c | 30 ++++++++++++++ drivers/net/sfc/falcon.c | 2 + drivers/net/sfc/net_driver.h | 3 ++ 5 files changed, 84 insertions(+), 50 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b016719d8f6..4b7168fc546 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1754,58 +1754,49 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) rc = efx->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); - ok = false; + goto fail; } + if (!ok) + goto fail; + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { - if (ok) { - rc = efx->phy_op->init(efx); - if (rc) - ok = false; - if (efx->phy_op->reconfigure(efx)) - EFX_ERR(efx, "could not restore PHY settings\n"); - } - if (!ok) - efx->port_initialized = false; + rc = efx->phy_op->init(efx); + if (rc) + goto fail; + if (efx->phy_op->reconfigure(efx)) + EFX_ERR(efx, "could not restore PHY settings\n"); } - if (ok) { - efx->mac_op->reconfigure(efx); + efx->mac_op->reconfigure(efx); - efx_init_channels(efx); - } + efx_init_channels(efx); + + mutex_unlock(&efx->spi_lock); + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + return 0; + +fail: + efx->port_initialized = false; mutex_unlock(&efx->spi_lock); mutex_unlock(&efx->mac_lock); - if (ok) - efx_start_all(efx); return rc; } -/* Reset the NIC as transparently as possible. Do not reset the PHY - * Note that the reset may fail, in which case the card will be left - * in a most-probably-unusable state. - * - * This function will sleep. You cannot reset from within an atomic - * state; use efx_schedule_reset() instead. +/* Reset the NIC using the specified method. Note that the reset may + * fail, in which case the card will be left in an unusable state. * - * Grabs the rtnl_lock. + * Caller must hold the rtnl_lock. */ -static int efx_reset(struct efx_nic *efx) +int efx_reset(struct efx_nic *efx, enum reset_type method) { - enum reset_type method = efx->reset_pending; - int rc = 0; - - /* Serialise with kernel interfaces */ - rtnl_lock(); - - /* If we're not RUNNING then don't reset. Leave the reset_pending - * flag set so that efx_pci_probe_main will be retried */ - if (efx->state != STATE_RUNNING) { - EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); - goto out_unlock; - } + int rc, rc2; + bool disabled; EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); @@ -1814,7 +1805,7 @@ static int efx_reset(struct efx_nic *efx) rc = efx->type->reset(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); - goto out_disable; + goto out; } /* Allow resets to be rescheduled. */ @@ -1826,25 +1817,22 @@ static int efx_reset(struct efx_nic *efx) * can respond to requests. */ pci_set_master(efx->pci_dev); +out: /* Leave device stopped if necessary */ - if (method == RESET_TYPE_DISABLE) { - efx_reset_up(efx, method, false); - rc = -EIO; - } else { - rc = efx_reset_up(efx, method, true); + disabled = rc || method == RESET_TYPE_DISABLE; + rc2 = efx_reset_up(efx, method, !disabled); + if (rc2) { + disabled = true; + if (!rc) + rc = rc2; } -out_disable: - if (rc) { + if (disabled) { EFX_ERR(efx, "has been disabled\n"); efx->state = STATE_DISABLED; - dev_close(efx->net_dev); } else { EFX_LOG(efx, "reset complete\n"); } - -out_unlock: - rtnl_unlock(); return rc; } @@ -1853,9 +1841,19 @@ out_unlock: */ static void efx_reset_work(struct work_struct *data) { - struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); + struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); - efx_reset(nic); + /* If we're not RUNNING then don't reset. Leave the reset_pending + * flag set so that efx_pci_probe_main will be retried */ + if (efx->state != STATE_RUNNING) { + EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); + return; + } + + rtnl_lock(); + if (efx_reset(efx, efx->reset_pending)) + dev_close(efx->net_dev); + rtnl_unlock(); } void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index c7850032158..fa40c7b66d7 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -71,6 +71,7 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev, extern const struct ethtool_ops efx_ethtool_ops; /* Reset handling */ +extern int efx_reset(struct efx_nic *efx, enum reset_type method); extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index b4c6ea1b9c0..29aa83c2a0d 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -754,6 +754,35 @@ static int efx_ethtool_set_wol(struct net_device *net_dev, return efx->type->set_wol(efx, wol->wolopts); } +extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) +{ + struct efx_nic *efx = netdev_priv(net_dev); + enum reset_type method; + enum { + ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | + ETH_RESET_OFFLOAD | ETH_RESET_MAC) + }; + + /* Check for minimal reset flags */ + if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE) + return -EINVAL; + *flags ^= ETH_RESET_EFX_INVISIBLE; + method = RESET_TYPE_INVISIBLE; + + if (*flags & ETH_RESET_PHY) { + *flags ^= ETH_RESET_PHY; + method = RESET_TYPE_ALL; + } + + if ((*flags & efx->type->reset_world_flags) == + efx->type->reset_world_flags) { + *flags ^= efx->type->reset_world_flags; + method = RESET_TYPE_WORLD; + } + + return efx_reset(efx, method); +} + const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, @@ -784,4 +813,5 @@ const struct ethtool_ops efx_ethtool_ops = { .get_ethtool_stats = efx_ethtool_get_stats, .get_wol = efx_ethtool_get_wol, .set_wol = efx_ethtool_set_wol, + .reset = efx_ethtool_reset, }; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 8f2c5830553..6a96c699e15 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -3305,6 +3305,7 @@ struct efx_nic_type falcon_a1_nic_type = { .phys_addr_channels = 4, .tx_dc_base = 0x130000, .rx_dc_base = 0x100000, + .reset_world_flags = ETH_RESET_IRQ, }; struct efx_nic_type falcon_b0_nic_type = { @@ -3348,5 +3349,6 @@ struct efx_nic_type falcon_b0_nic_type = { * channels */ .tx_dc_base = 0x130000, .rx_dc_base = 0x100000, + .reset_world_flags = ETH_RESET_IRQ, }; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index a9fde82aeea..58bf761d731 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -880,6 +880,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * descriptors * @tx_dc_base: Base address in SRAM of TX queue descriptor caches * @rx_dc_base: Base address in SRAM of RX queue descriptor caches + * @reset_world_flags: Flags for additional components covered by + * reset method RESET_TYPE_WORLD */ struct efx_nic_type { int (*probe)(struct efx_nic *efx); @@ -915,6 +917,7 @@ struct efx_nic_type { unsigned int phys_addr_channels; unsigned int tx_dc_base; unsigned int rx_dc_base; + u32 reset_world_flags; }; /************************************************************************** -- cgit v1.2.3-70-g09d2 From 152b6a62aea2d43359dd37004e9c218bf7bdeb3b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 03:43:56 +0000 Subject: sfc: Separate shared NIC code from Falcon-specific and rename accordingly Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 30 +-- drivers/net/sfc/ethtool.c | 4 +- drivers/net/sfc/falcon.c | 507 +++++++++++++++++++++++---------------------- drivers/net/sfc/falcon.h | 80 ++++--- drivers/net/sfc/rx.c | 10 +- drivers/net/sfc/selftest.c | 4 +- drivers/net/sfc/tx.c | 12 +- 7 files changed, 341 insertions(+), 306 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4b7168fc546..e5c33c66eda 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -213,7 +213,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) !channel->enabled)) return 0; - rx_packets = falcon_process_eventq(channel, rx_quota); + rx_packets = efx_nic_process_eventq(channel, rx_quota); if (rx_packets == 0) return 0; @@ -245,7 +245,7 @@ static inline void efx_channel_processed(struct efx_channel *channel) channel->work_pending = false; smp_wmb(); - falcon_eventq_read_ack(channel); + efx_nic_eventq_read_ack(channel); } /* NAPI poll handler @@ -316,7 +316,7 @@ void efx_process_channel_now(struct efx_channel *channel) BUG_ON(!channel->enabled); /* Disable interrupts and wait for ISRs to complete */ - falcon_disable_interrupts(efx); + efx_nic_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); if (channel->irq) @@ -333,7 +333,7 @@ void efx_process_channel_now(struct efx_channel *channel) efx_channel_processed(channel); napi_enable(&channel->napi_str); - falcon_enable_interrupts(efx); + efx_nic_enable_interrupts(efx); } /* Create event queue @@ -345,7 +345,7 @@ static int efx_probe_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel); - return falcon_probe_eventq(channel); + return efx_nic_probe_eventq(channel); } /* Prepare channel's event queue */ @@ -355,21 +355,21 @@ static void efx_init_eventq(struct efx_channel *channel) channel->eventq_read_ptr = 0; - falcon_init_eventq(channel); + efx_nic_init_eventq(channel); } static void efx_fini_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel); - falcon_fini_eventq(channel); + efx_nic_fini_eventq(channel); } static void efx_remove_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel); - falcon_remove_eventq(channel); + efx_nic_remove_eventq(channel); } /************************************************************************** @@ -535,7 +535,7 @@ static void efx_fini_channels(struct efx_nic *efx) EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); - rc = falcon_flush_queues(efx); + rc = efx_nic_flush_queues(efx); if (rc) EFX_ERR(efx, "failed to flush queues\n"); else @@ -1172,7 +1172,7 @@ static void efx_start_all(struct efx_nic *efx) efx_for_each_channel(channel, efx) efx_start_channel(channel); - falcon_enable_interrupts(efx); + efx_nic_enable_interrupts(efx); /* Start the hardware monitor if there is one. Otherwise (we're link * event driven), we have to poll the PHY because after an event queue @@ -1226,7 +1226,7 @@ static void efx_stop_all(struct efx_nic *efx) efx->type->stop_stats(efx); /* Disable interrupts and wait for ISR to complete */ - falcon_disable_interrupts(efx); + efx_nic_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); efx_for_each_channel(channel, efx) { @@ -1286,8 +1286,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; - unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION); - unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION); + unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); + unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); EFX_ASSERT_RESET_SERIALISED(efx); @@ -2042,7 +2042,7 @@ static void efx_fini_struct(struct efx_nic *efx) */ static void efx_pci_remove_main(struct efx_nic *efx) { - falcon_fini_interrupt(efx); + efx_nic_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); efx->type->fini(efx); @@ -2119,7 +2119,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_init_channels(efx); - rc = falcon_init_interrupt(efx); + rc = efx_nic_init_interrupt(efx); if (rc) goto fail5; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 50639752763..e86cbca75ea 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -611,8 +611,8 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation; - coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; - coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; + coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; + coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; return 0; } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 61cc9948b23..2e4c7111463 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -69,8 +69,8 @@ default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) * This also has an effect on RX/TX arbitration */ -static int rx_xoff_thresh_bytes = -1; -module_param(rx_xoff_thresh_bytes, int, 0644); +int efx_nic_rx_xoff_thresh = -1; +module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644); MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); /* RX FIFO XON watermark @@ -79,21 +79,21 @@ MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); * watermark send XON. Only used if TX flow control is enabled (ethtool -A) * This also has an effect on RX/TX arbitration */ -static int rx_xon_thresh_bytes = -1; -module_param(rx_xon_thresh_bytes, int, 0644); +int efx_nic_rx_xon_thresh = -1; +module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644); MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); -/* If FALCON_MAX_INT_ERRORS internal errors occur within - * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and +/* If EFX_MAX_INT_ERRORS internal errors occur within + * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and * disable it. */ -#define FALCON_INT_ERROR_EXPIRE 3600 -#define FALCON_MAX_INT_ERRORS 5 +#define EFX_INT_ERROR_EXPIRE 3600 +#define EFX_MAX_INT_ERRORS 5 /* 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 +#define EFX_FLUSH_INTERVAL 10 +#define EFX_FLUSH_POLL_COUNT 100 /************************************************************************** * @@ -103,30 +103,27 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); */ /* Size and alignment of special buffers (4KB) */ -#define FALCON_BUF_SIZE 4096 +#define EFX_BUF_SIZE 4096 /* Depth of RX flush request fifo */ -#define FALCON_RX_FLUSH_COUNT 4 - -#define FALCON_IS_DUAL_FUNC(efx) \ - (efx_nic_rev(efx) < EFX_REV_FALCON_B0) +#define EFX_RX_FLUSH_COUNT 4 /************************************************************************** * - * Falcon hardware access + * Solarstorm hardware access * **************************************************************************/ -static inline void falcon_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, - unsigned int index) +static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, + unsigned int index) { efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base, value, index); } /* Read the current event from the event queue */ -static inline efx_qword_t *falcon_event(struct efx_channel *channel, - unsigned int index) +static inline efx_qword_t *efx_event(struct efx_channel *channel, + unsigned int index) { return (((efx_qword_t *) (channel->eventq.addr)) + index); } @@ -141,7 +138,7 @@ static inline efx_qword_t *falcon_event(struct efx_channel *channel, * Note that using a single 64-bit comparison is incorrect; even * though the CPU read will be atomic, the DMA write may not be. */ -static inline int falcon_event_present(efx_qword_t *event) +static inline int efx_event_present(efx_qword_t *event) { return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | EFX_DWORD_IS_ALL_ONES(event->dword[1]))); @@ -205,22 +202,21 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { /************************************************************************** * - * Falcon special buffer handling + * Special buffer handling * Special buffers are used for event queues and the TX and RX * descriptor rings. * *************************************************************************/ /* - * Initialise a Falcon special buffer + * Initialise a special buffer * * This will define a buffer (previously allocated via - * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing + * efx_alloc_special_buffer()) in the buffer table, allowing * it to be used for event queues, descriptor rings etc. */ static void -falcon_init_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) +efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) { efx_qword_t buf_desc; int index; @@ -239,14 +235,13 @@ falcon_init_special_buffer(struct efx_nic *efx, FRF_AZ_BUF_ADR_REGION, 0, FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12, FRF_AZ_BUF_OWNER_ID_FBUF, 0); - falcon_write_buf_tbl(efx, &buf_desc, index); + efx_write_buf_tbl(efx, &buf_desc, index); } } -/* Unmaps a buffer from Falcon and clears the buffer table entries */ +/* Unmaps a buffer and clears the buffer table entries */ static void -falcon_fini_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) +efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) { efx_oword_t buf_tbl_upd; unsigned int start = buffer->index; @@ -267,27 +262,27 @@ falcon_fini_special_buffer(struct efx_nic *efx, } /* - * Allocate a new Falcon special buffer + * Allocate a new special buffer * * This allocates memory for a new buffer, clears it and allocates a - * new buffer ID range. It does not write into Falcon's buffer table. + * new buffer ID range. It does not write into the buffer table. * - * This call will allocate 4KB buffers, since Falcon can't use 8KB - * buffers for event queues and descriptor rings. + * This call will allocate 4KB buffers, since 8KB buffers can't be + * used for event queues and descriptor rings. */ -static int falcon_alloc_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer, - unsigned int len) +static int efx_alloc_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer, + unsigned int len) { - len = ALIGN(len, FALCON_BUF_SIZE); + len = ALIGN(len, EFX_BUF_SIZE); buffer->addr = pci_alloc_consistent(efx->pci_dev, len, &buffer->dma_addr); if (!buffer->addr) return -ENOMEM; buffer->len = len; - buffer->entries = len / FALCON_BUF_SIZE; - BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1)); + buffer->entries = len / EFX_BUF_SIZE; + BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1)); /* All zeros is a potentially valid event so memset to 0xff */ memset(buffer->addr, 0xff, len); @@ -305,8 +300,8 @@ static int falcon_alloc_special_buffer(struct efx_nic *efx, return 0; } -static void falcon_free_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) +static void +efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) { if (!buffer->addr) return; @@ -325,13 +320,13 @@ static void falcon_free_special_buffer(struct efx_nic *efx, /************************************************************************** * - * Falcon generic buffer handling + * Generic buffer handling * These buffers are used for interrupt status and MAC stats * **************************************************************************/ -static int falcon_alloc_buffer(struct efx_nic *efx, - struct efx_buffer *buffer, unsigned int len) +int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, + unsigned int len) { buffer->addr = pci_alloc_consistent(efx->pci_dev, len, &buffer->dma_addr); @@ -342,7 +337,7 @@ static int falcon_alloc_buffer(struct efx_nic *efx, return 0; } -static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) +void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) { if (buffer->addr) { pci_free_consistent(efx->pci_dev, buffer->len, @@ -353,21 +348,21 @@ static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) /************************************************************************** * - * Falcon TX path + * TX path * **************************************************************************/ /* Returns a pointer to the specified transmit descriptor in the TX * descriptor queue belonging to the specified channel. */ -static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue, - unsigned int index) +static inline efx_qword_t * +efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) { return (((efx_qword_t *) (tx_queue->txd.addr)) + index); } /* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ -static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) +static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue) { unsigned write_ptr; efx_dword_t reg; @@ -383,7 +378,7 @@ static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) * descriptor in the hardware TX descriptor ring (in host memory), and * write a doorbell. */ -void falcon_push_buffers(struct efx_tx_queue *tx_queue) +void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) { struct efx_tx_buffer *buffer; @@ -395,7 +390,7 @@ void falcon_push_buffers(struct efx_tx_queue *tx_queue) do { write_ptr = tx_queue->write_count & EFX_TXQ_MASK; buffer = &tx_queue->buffer[write_ptr]; - txd = falcon_tx_desc(tx_queue, write_ptr); + txd = efx_tx_desc(tx_queue, write_ptr); ++tx_queue->write_count; /* Create TX descriptor ring entry */ @@ -407,20 +402,20 @@ void falcon_push_buffers(struct efx_tx_queue *tx_queue) } while (tx_queue->write_count != tx_queue->insert_count); wmb(); /* Ensure descriptors are written before they are fetched */ - falcon_notify_tx_desc(tx_queue); + efx_notify_tx_desc(tx_queue); } /* Allocate hardware resources for a TX queue */ -int falcon_probe_tx(struct efx_tx_queue *tx_queue) +int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || EFX_TXQ_SIZE & EFX_TXQ_MASK); - return falcon_alloc_special_buffer(efx, &tx_queue->txd, - EFX_TXQ_SIZE * sizeof(efx_qword_t)); + return efx_alloc_special_buffer(efx, &tx_queue->txd, + EFX_TXQ_SIZE * sizeof(efx_qword_t)); } -void falcon_init_tx(struct efx_tx_queue *tx_queue) +void efx_nic_init_tx(struct efx_tx_queue *tx_queue) { efx_oword_t tx_desc_ptr; struct efx_nic *efx = tx_queue->efx; @@ -428,7 +423,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue) tx_queue->flushed = FLUSH_NONE; /* Pin TX descriptor ring */ - falcon_init_special_buffer(efx, &tx_queue->txd); + efx_init_special_buffer(efx, &tx_queue->txd); /* Push TX descriptor ring to card */ EFX_POPULATE_OWORD_10(tx_desc_ptr, @@ -470,7 +465,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue) } } -static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) +static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; efx_oword_t tx_flush_descq; @@ -484,7 +479,7 @@ static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ); } -void falcon_fini_tx(struct efx_tx_queue *tx_queue) +void efx_nic_fini_tx(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; efx_oword_t tx_desc_ptr; @@ -498,36 +493,36 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue) tx_queue->queue); /* Unpin TX descriptor ring */ - falcon_fini_special_buffer(efx, &tx_queue->txd); + efx_fini_special_buffer(efx, &tx_queue->txd); } /* Free buffers backing TX queue */ -void falcon_remove_tx(struct efx_tx_queue *tx_queue) +void efx_nic_remove_tx(struct efx_tx_queue *tx_queue) { - falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd); + efx_free_special_buffer(tx_queue->efx, &tx_queue->txd); } /************************************************************************** * - * Falcon RX path + * RX path * **************************************************************************/ /* Returns a pointer to the specified descriptor in the RX descriptor queue */ -static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue, - unsigned int index) +static inline efx_qword_t * +efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) { return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); } /* This creates an entry in the RX descriptor queue */ -static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue, - unsigned index) +static inline void +efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index) { struct efx_rx_buffer *rx_buf; efx_qword_t *rxd; - rxd = falcon_rx_desc(rx_queue, index); + rxd = efx_rx_desc(rx_queue, index); rx_buf = efx_rx_buffer(rx_queue, index); EFX_POPULATE_QWORD_3(*rxd, FSF_AZ_RX_KER_BUF_SIZE, @@ -540,15 +535,15 @@ static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue, /* This writes to the RX_DESC_WPTR register for the specified receive * descriptor ring. */ -void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue) +void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue) { efx_dword_t reg; unsigned write_ptr; while (rx_queue->notified_count != rx_queue->added_count) { - falcon_build_rx_desc(rx_queue, - rx_queue->notified_count & - EFX_RXQ_MASK); + efx_build_rx_desc(rx_queue, + rx_queue->notified_count & + EFX_RXQ_MASK); ++rx_queue->notified_count; } @@ -559,16 +554,16 @@ void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue) FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); } -int falcon_probe_rx(struct efx_rx_queue *rx_queue) +int efx_nic_probe_rx(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || EFX_RXQ_SIZE & EFX_RXQ_MASK); - return falcon_alloc_special_buffer(efx, &rx_queue->rxd, - EFX_RXQ_SIZE * sizeof(efx_qword_t)); + return efx_alloc_special_buffer(efx, &rx_queue->rxd, + EFX_RXQ_SIZE * sizeof(efx_qword_t)); } -void falcon_init_rx(struct efx_rx_queue *rx_queue) +void efx_nic_init_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; @@ -582,7 +577,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue) rx_queue->flushed = FLUSH_NONE; /* Pin RX descriptor ring */ - falcon_init_special_buffer(efx, &rx_queue->rxd); + efx_init_special_buffer(efx, &rx_queue->rxd); /* Push RX descriptor ring to card */ EFX_POPULATE_OWORD_10(rx_desc_ptr, @@ -603,7 +598,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue) rx_queue->queue); } -static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) +static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; efx_oword_t rx_flush_descq; @@ -617,7 +612,7 @@ static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); } -void falcon_fini_rx(struct efx_rx_queue *rx_queue) +void efx_nic_fini_rx(struct efx_rx_queue *rx_queue) { efx_oword_t rx_desc_ptr; struct efx_nic *efx = rx_queue->efx; @@ -631,18 +626,18 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue) rx_queue->queue); /* Unpin RX descriptor ring */ - falcon_fini_special_buffer(efx, &rx_queue->rxd); + efx_fini_special_buffer(efx, &rx_queue->rxd); } /* Free buffers backing RX queue */ -void falcon_remove_rx(struct efx_rx_queue *rx_queue) +void efx_nic_remove_rx(struct efx_rx_queue *rx_queue) { - falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd); + efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd); } /************************************************************************** * - * Falcon event queue processing + * Event queue processing * Event queues are processed by per-channel tasklets. * **************************************************************************/ @@ -656,7 +651,7 @@ void falcon_remove_rx(struct efx_rx_queue *rx_queue) * whereas channel->eventq_read_ptr contains the index of the "next to * read" event. */ -void falcon_eventq_read_ack(struct efx_channel *channel) +void efx_nic_eventq_read_ack(struct efx_channel *channel) { efx_dword_t reg; struct efx_nic *efx = channel->efx; @@ -667,7 +662,7 @@ void falcon_eventq_read_ack(struct efx_channel *channel) } /* Use HW to insert a SW defined event */ -void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) +void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) { efx_oword_t drv_ev_reg; @@ -683,11 +678,11 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) /* Handle a transmit completion event * - * Falcon batches TX completion events; the message we receive is of + * The NIC batches TX completion events; the message we receive is of * the form "complete all TX events up to this index". */ -static void falcon_handle_tx_event(struct efx_channel *channel, - efx_qword_t *event) +static void +efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) { unsigned int tx_ev_desc_ptr; unsigned int tx_ev_q_label; @@ -710,7 +705,7 @@ static void falcon_handle_tx_event(struct efx_channel *channel, if (efx_dev_registered(efx)) netif_tx_lock(efx->net_dev); - falcon_notify_tx_desc(tx_queue); + efx_notify_tx_desc(tx_queue); if (efx_dev_registered(efx)) netif_tx_unlock(efx->net_dev); } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && @@ -724,10 +719,10 @@ static void falcon_handle_tx_event(struct efx_channel *channel, } /* Detect errors included in the rx_evt_pkt_ok bit. */ -static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, - const efx_qword_t *event, - bool *rx_ev_pkt_ok, - bool *discard) +static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, + const efx_qword_t *event, + bool *rx_ev_pkt_ok, + bool *discard) { struct efx_nic *efx = rx_queue->efx; bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; @@ -799,8 +794,8 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, } /* Handle receive events that are not in-order. */ -static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, - unsigned index) +static void +efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) { struct efx_nic *efx = rx_queue->efx; unsigned expected, dropped; @@ -816,13 +811,13 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, /* Handle a packet received event * - * Falcon silicon gives a "discard" flag if it's a unicast packet with the + * The NIC gives a "discard" flag if it's a unicast packet with the * wrong destination address * Also "is multicast" and "matches multicast filter" flags can be used to * discard non-matching multicast packets. */ -static void falcon_handle_rx_event(struct efx_channel *channel, - const efx_qword_t *event) +static void +efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) { unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; @@ -845,19 +840,18 @@ static void falcon_handle_rx_event(struct efx_channel *channel, rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; if (unlikely(rx_ev_desc_ptr != expected_ptr)) - falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); + efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); if (likely(rx_ev_pkt_ok)) { - /* If packet is marked as OK and packet type is TCP/IPv4 or - * UDP/IPv4, then we can rely on the hardware checksum. + /* If packet is marked as OK and packet type is TCP/IP or + * UDP/IP, then we can rely on the hardware checksum. */ checksummed = likely(efx->rx_checksum_enabled) && - (rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP || - rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP); + (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); } else { - falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, - &discard); + efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); checksummed = false; } @@ -881,8 +875,8 @@ static void falcon_handle_rx_event(struct efx_channel *channel, } /* Global events are basically PHY events */ -static void falcon_handle_global_event(struct efx_channel *channel, - efx_qword_t *event) +static void +efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; bool handled = false; @@ -918,8 +912,8 @@ static void falcon_handle_global_event(struct efx_channel *channel, EFX_QWORD_VAL(*event)); } -static void falcon_handle_driver_event(struct efx_channel *channel, - efx_qword_t *event) +static void +efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; unsigned int ev_sub_code; @@ -980,7 +974,7 @@ static void falcon_handle_driver_event(struct efx_channel *channel, } } -int falcon_process_eventq(struct efx_channel *channel, int rx_quota) +int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) { unsigned int read_ptr; efx_qword_t event, *p_event; @@ -990,10 +984,10 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota) read_ptr = channel->eventq_read_ptr; do { - p_event = falcon_event(channel, read_ptr); + p_event = efx_event(channel, read_ptr); event = *p_event; - if (!falcon_event_present(&event)) + if (!efx_event_present(&event)) /* End of events */ break; @@ -1007,11 +1001,11 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota) switch (ev_code) { case FSE_AZ_EV_CODE_RX_EV: - falcon_handle_rx_event(channel, &event); + efx_handle_rx_event(channel, &event); ++rx_packets; break; case FSE_AZ_EV_CODE_TX_EV: - falcon_handle_tx_event(channel, &event); + efx_handle_tx_event(channel, &event); break; case FSE_AZ_EV_CODE_DRV_GEN_EV: channel->eventq_magic = EFX_QWORD_FIELD( @@ -1021,10 +1015,10 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota) EFX_QWORD_VAL(event)); break; case FSE_AZ_EV_CODE_GLOBAL_EV: - falcon_handle_global_event(channel, &event); + efx_handle_global_event(channel, &event); break; case FSE_AZ_EV_CODE_DRIVER_EV: - falcon_handle_driver_event(channel, &event); + efx_handle_driver_event(channel, &event); break; default: EFX_ERR(channel->efx, "channel %d unknown event type %d" @@ -1066,16 +1060,16 @@ static void falcon_push_irq_moderation(struct efx_channel *channel) } /* Allocate buffer table entries for event queue */ -int falcon_probe_eventq(struct efx_channel *channel) +int efx_nic_probe_eventq(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || EFX_EVQ_SIZE & EFX_EVQ_MASK); - return falcon_alloc_special_buffer(efx, &channel->eventq, - EFX_EVQ_SIZE * sizeof(efx_qword_t)); + return efx_alloc_special_buffer(efx, &channel->eventq, + EFX_EVQ_SIZE * sizeof(efx_qword_t)); } -void falcon_init_eventq(struct efx_channel *channel) +void efx_nic_init_eventq(struct efx_channel *channel) { efx_oword_t evq_ptr; struct efx_nic *efx = channel->efx; @@ -1085,7 +1079,7 @@ void falcon_init_eventq(struct efx_channel *channel) channel->eventq.index + channel->eventq.entries - 1); /* Pin event queue buffer */ - falcon_init_special_buffer(efx, &channel->eventq); + efx_init_special_buffer(efx, &channel->eventq); /* Fill event queue with all ones (i.e. empty events) */ memset(channel->eventq.addr, 0xff, channel->eventq.len); @@ -1098,10 +1092,10 @@ void falcon_init_eventq(struct efx_channel *channel) efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, channel->channel); - falcon_push_irq_moderation(channel); + efx->type->push_irq_moderation(channel); } -void falcon_fini_eventq(struct efx_channel *channel) +void efx_nic_fini_eventq(struct efx_channel *channel) { efx_oword_t eventq_ptr; struct efx_nic *efx = channel->efx; @@ -1112,13 +1106,13 @@ void falcon_fini_eventq(struct efx_channel *channel) channel->channel); /* Unpin event queue */ - falcon_fini_special_buffer(efx, &channel->eventq); + efx_fini_special_buffer(efx, &channel->eventq); } /* Free buffers backing event queue */ -void falcon_remove_eventq(struct efx_channel *channel) +void efx_nic_remove_eventq(struct efx_channel *channel) { - falcon_free_special_buffer(channel->efx, &channel->eventq); + efx_free_special_buffer(channel->efx, &channel->eventq); } @@ -1126,14 +1120,14 @@ void falcon_remove_eventq(struct efx_channel *channel) * process_eventq() should pick up the event and place the value of * "magic" into channel->eventq_magic; */ -void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) +void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic) { efx_qword_t test_event; EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE, FSE_AZ_EV_CODE_DRV_GEN_EV, FSF_AZ_DRV_GEN_EV_MAGIC, magic); - falcon_generate_event(channel, &test_event); + efx_generate_event(channel, &test_event); } /************************************************************************** @@ -1143,7 +1137,7 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) **************************************************************************/ -static void falcon_poll_flush_events(struct efx_nic *efx) +static void efx_poll_flush_events(struct efx_nic *efx) { struct efx_channel *channel = &efx->channel[0]; struct efx_tx_queue *tx_queue; @@ -1152,11 +1146,11 @@ static void falcon_poll_flush_events(struct efx_nic *efx) unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; do { - efx_qword_t *event = falcon_event(channel, read_ptr); + efx_qword_t *event = efx_event(channel, read_ptr); int ev_code, ev_sub_code, ev_queue; bool ev_failed; - if (!falcon_event_present(event)) + if (!efx_event_present(event)) break; ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE); @@ -1208,7 +1202,7 @@ static void falcon_prepare_flush(struct efx_nic *efx) /* 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) +int efx_nic_flush_queues(struct efx_nic *efx) { struct efx_rx_queue *rx_queue; struct efx_tx_queue *tx_queue; @@ -1219,22 +1213,22 @@ int falcon_flush_queues(struct efx_nic *efx) /* Flush all tx queues in parallel */ efx_for_each_tx_queue(tx_queue, efx) - falcon_flush_tx_queue(tx_queue); + efx_flush_tx_queue(tx_queue); /* 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) { + for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) { 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) + if (rx_pending == EFX_RX_FLUSH_COUNT) break; if (rx_queue->flushed == FLUSH_FAILED || rx_queue->flushed == FLUSH_NONE) { - falcon_flush_rx_queue(rx_queue); + efx_flush_rx_queue(rx_queue); ++rx_pending; } } @@ -1246,8 +1240,8 @@ int falcon_flush_queues(struct efx_nic *efx) if (rx_pending == 0 && tx_pending == 0) return 0; - msleep(FALCON_FLUSH_INTERVAL); - falcon_poll_flush_events(efx); + msleep(EFX_FLUSH_INTERVAL); + efx_poll_flush_events(efx); } /* Mark the queues as all flushed. We're going to return failure @@ -1273,15 +1267,15 @@ int falcon_flush_queues(struct efx_nic *efx) /************************************************************************** * - * Falcon hardware interrupts + * Hardware interrupts * The hardware interrupt handler does very little work; all the event * queue processing is carried out by per-channel tasklets. * **************************************************************************/ -/* Enable/disable/generate Falcon interrupts */ -static inline void falcon_interrupts(struct efx_nic *efx, int enabled, - int force) +/* Enable/disable/generate interrupts */ +static inline void efx_nic_interrupts(struct efx_nic *efx, + bool enabled, bool force) { efx_oword_t int_en_reg_ker; @@ -1291,7 +1285,7 @@ static inline void falcon_interrupts(struct efx_nic *efx, int enabled, efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); } -void falcon_enable_interrupts(struct efx_nic *efx) +void efx_nic_enable_interrupts(struct efx_nic *efx) { struct efx_channel *channel; @@ -1299,7 +1293,7 @@ void falcon_enable_interrupts(struct efx_nic *efx) wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ /* Enable interrupts */ - falcon_interrupts(efx, 1, 0); + efx_nic_interrupts(efx, true, false); /* Force processing of all the channels to get the EVQ RPTRs up to date */ @@ -1307,19 +1301,19 @@ void falcon_enable_interrupts(struct efx_nic *efx) efx_schedule_channel(channel); } -void falcon_disable_interrupts(struct efx_nic *efx) +void efx_nic_disable_interrupts(struct efx_nic *efx) { /* Disable interrupts */ - falcon_interrupts(efx, 0, 0); + efx_nic_interrupts(efx, false, false); } -/* Generate a Falcon test interrupt +/* Generate a test interrupt * Interrupt must already have been enabled, otherwise nasty things * may happen. */ -void falcon_generate_interrupt(struct efx_nic *efx) +void efx_nic_generate_interrupt(struct efx_nic *efx) { - falcon_interrupts(efx, 1, 1); + efx_nic_interrupts(efx, true, true); } /* Acknowledge a legacy interrupt from Falcon @@ -1332,7 +1326,7 @@ void falcon_generate_interrupt(struct efx_nic *efx) * * NB most hardware supports MSI interrupts */ -static inline void falcon_irq_ack_a1(struct efx_nic *efx) +inline void falcon_irq_ack_a1(struct efx_nic *efx) { efx_dword_t reg; @@ -1344,7 +1338,7 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx) /* Process a fatal interrupt * Disable bus mastering ASAP and schedule a reset */ -static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) +irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t *int_ker = efx->irq_status.addr; @@ -1372,18 +1366,18 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) /* Disable both devices */ pci_clear_master(efx->pci_dev); - if (FALCON_IS_DUAL_FUNC(efx)) + if (efx_nic_is_dual_func(efx)) pci_clear_master(nic_data->pci_dev2); - falcon_disable_interrupts(efx); + efx_nic_disable_interrupts(efx); /* Count errors and reset or disable the NIC accordingly */ if (efx->int_error_count == 0 || time_after(jiffies, efx->int_error_expire)) { efx->int_error_count = 0; efx->int_error_expire = - jiffies + FALCON_INT_ERROR_EXPIRE * HZ; + jiffies + EFX_INT_ERROR_EXPIRE * HZ; } - if (++efx->int_error_count < FALCON_MAX_INT_ERRORS) { + if (++efx->int_error_count < EFX_MAX_INT_ERRORS) { EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); } else { @@ -1395,10 +1389,10 @@ out: return IRQ_HANDLED; } -/* Handle a legacy interrupt from Falcon +/* Handle a legacy interrupt * Acknowledges the interrupt and schedule event queue processing. */ -static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) +static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) { struct efx_nic *efx = dev_id; efx_oword_t *int_ker = efx->irq_status.addr; @@ -1415,13 +1409,13 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) /* Check to see if we have a serious error condition */ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); + return efx_nic_fatal_interrupt(efx); /* Schedule processing of any interrupting queues */ efx_for_each_channel(channel, efx) { if ((queues & 1) || - falcon_event_present( - falcon_event(channel, channel->eventq_read_ptr))) { + efx_event_present( + efx_event(channel, channel->eventq_read_ptr))) { efx_schedule_channel(channel); result = IRQ_HANDLED; } @@ -1438,7 +1432,7 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) } -static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) +irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) { struct efx_nic *efx = dev_id; efx_oword_t *int_ker = efx->irq_status.addr; @@ -1461,7 +1455,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) /* Check to see if we have a serious error condition */ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); + return efx_nic_fatal_interrupt(efx); /* Determine interrupting queues, clear interrupt status * register and acknowledge the device interrupt. @@ -1484,14 +1478,14 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) return IRQ_HANDLED; } -/* Handle an MSI interrupt from Falcon +/* Handle an MSI interrupt * * Handle an MSI hardware interrupt. This routine schedules event * queue processing. No interrupt acknowledgement cycle is necessary. * Also, we never need to check that the interrupt is for us, since * MSI interrupts cannot be shared. */ -static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) +static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) { struct efx_channel *channel = dev_id; struct efx_nic *efx = channel->efx; @@ -1505,7 +1499,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) /* Check to see if we have a serious error condition */ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); + return efx_nic_fatal_interrupt(efx); /* Schedule processing of the channel */ efx_schedule_channel(channel); @@ -1517,7 +1511,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) /* Setup RSS indirection table. * This maps from the hash value of the packet to RXQ */ -static void falcon_setup_rss_indir_table(struct efx_nic *efx) +static void efx_setup_rss_indir_table(struct efx_nic *efx) { int i = 0; unsigned long offset; @@ -1539,7 +1533,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx) /* Hook interrupt handler(s) * Try MSI and then legacy interrupts. */ -int falcon_init_interrupt(struct efx_nic *efx) +int efx_nic_init_interrupt(struct efx_nic *efx) { struct efx_channel *channel; int rc; @@ -1547,7 +1541,7 @@ int falcon_init_interrupt(struct efx_nic *efx) if (!EFX_INT_MODE_USE_MSI(efx)) { irq_handler_t handler; if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) - handler = falcon_legacy_interrupt_b0; + handler = efx_legacy_interrupt; else handler = falcon_legacy_interrupt_a1; @@ -1563,7 +1557,7 @@ int falcon_init_interrupt(struct efx_nic *efx) /* Hook MSI or MSI-X interrupt */ efx_for_each_channel(channel, efx) { - rc = request_irq(channel->irq, falcon_msi_interrupt, + rc = request_irq(channel->irq, efx_msi_interrupt, IRQF_PROBE_SHARED, /* Not shared */ channel->name, channel); if (rc) { @@ -1581,7 +1575,7 @@ int falcon_init_interrupt(struct efx_nic *efx) return rc; } -void falcon_fini_interrupt(struct efx_nic *efx) +void efx_nic_fini_interrupt(struct efx_nic *efx) { struct efx_channel *channel; efx_oword_t reg; @@ -2322,8 +2316,8 @@ static int falcon_probe_port(struct efx_nic *efx) efx->wanted_fc = EFX_FC_RX; /* Allocate buffer for stats */ - rc = falcon_alloc_buffer(efx, &efx->stats_buffer, - FALCON_MAC_STATS_SIZE); + rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, + FALCON_MAC_STATS_SIZE); if (rc) return rc; EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", @@ -2336,7 +2330,7 @@ static int falcon_probe_port(struct efx_nic *efx) static void falcon_remove_port(struct efx_nic *efx) { - falcon_free_buffer(efx, &efx->stats_buffer); + efx_nic_free_buffer(efx, &efx->stats_buffer); } /************************************************************************** @@ -2414,11 +2408,7 @@ static int falcon_test_nvram(struct efx_nic *efx) return falcon_read_nvram(efx, NULL); } -/* Registers tested in the falcon register test */ -static struct { - unsigned address; - efx_oword_t mask; -} efx_test_registers[] = { +static const struct efx_nic_register_test falcon_b0_register_tests[] = { { FR_AZ_ADR_REGION, EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, { FR_AZ_RX_CFG, @@ -2464,7 +2454,9 @@ static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); } -static int falcon_b0_test_registers(struct efx_nic *efx) +int efx_nic_test_registers(struct efx_nic *efx, + const struct efx_nic_register_test *regs, + size_t n_regs) { unsigned address = 0, i, j; efx_oword_t mask, imask, original, reg, buf; @@ -2472,9 +2464,9 @@ static int falcon_b0_test_registers(struct efx_nic *efx) /* 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; + for (i = 0; i < n_regs; ++i) { + address = regs[i].address; + mask = imask = regs[i].mask; EFX_INVERT_OWORD(imask); efx_reado(efx, &original, address); @@ -2517,6 +2509,12 @@ fail: return -EIO; } +static int falcon_b0_test_registers(struct efx_nic *efx) +{ + return efx_nic_test_registers(efx, falcon_b0_register_tests, + ARRAY_SIZE(falcon_b0_register_tests)); +} + /************************************************************************** * * Device reset @@ -2542,7 +2540,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) "function prior to hardware reset\n"); goto fail1; } - if (FALCON_IS_DUAL_FUNC(efx)) { + if (efx_nic_is_dual_func(efx)) { rc = pci_save_state(nic_data->pci_dev2); if (rc) { EFX_ERR(efx, "failed to backup PCI state of " @@ -2577,7 +2575,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) /* Restore PCI configuration if needed */ if (method == RESET_TYPE_WORLD) { - if (FALCON_IS_DUAL_FUNC(efx)) { + if (efx_nic_is_dual_func(efx)) { rc = pci_restore_state(nic_data->pci_dev2); if (rc) { EFX_ERR(efx, "failed to restore PCI config for " @@ -2800,16 +2798,22 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) return rc; } +u32 efx_nic_fpga_ver(struct efx_nic *efx) +{ + efx_oword_t altera_build; + + efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); + return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER); +} + /* Probe the NIC variant (revision, ASIC vs FPGA, function count, port * count, port speed). Set workaround and feature flags accordingly. */ static int falcon_probe_nic_variant(struct efx_nic *efx) { - efx_oword_t altera_build; efx_oword_t nic_stat; - efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); - if (EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER)) { + if (efx_nic_fpga_ver(efx) != 0) { EFX_ERR(efx, "Falcon FPGA not supported\n"); return -ENODEV; } @@ -2893,7 +2897,7 @@ static int falcon_probe_nic(struct efx_nic *efx) goto fail1; /* Probe secondary function if expected */ - if (FALCON_IS_DUAL_FUNC(efx)) { + if (efx_nic_is_dual_func(efx)) { struct pci_dev *dev = pci_dev_get(efx->pci_dev); while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID, @@ -2919,7 +2923,7 @@ static int falcon_probe_nic(struct efx_nic *efx) } /* Allocate memory for INT_KER */ - rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); + rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); if (rc) goto fail4; BUG_ON(efx->irq_status.dma_addr & 0x0f); @@ -2965,7 +2969,7 @@ static int falcon_probe_nic(struct efx_nic *efx) memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); fail5: falcon_remove_spi_devices(efx); - falcon_free_buffer(efx, &efx->irq_status); + efx_nic_free_buffer(efx, &efx->irq_status); fail4: fail3: if (nic_data->pci_dev2) { @@ -2988,8 +2992,8 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) const unsigned ctrl_xon_thr = 20; const unsigned ctrl_xoff_thr = 25; /* RX data FIFO thresholds (256-byte units; size varies) */ - int data_xon_thr = rx_xon_thresh_bytes >> 8; - int data_xoff_thr = rx_xoff_thresh_bytes >> 8; + int data_xon_thr = efx_nic_rx_xon_thresh >> 8; + int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8; efx_oword_t reg; efx_reado(efx, ®, FR_AZ_RX_CFG); @@ -3027,33 +3031,9 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) efx_writeo(efx, ®, FR_AZ_RX_CFG); } -/* This call performs hardware-specific global initialisation, such as - * defining the descriptor cache sizes and number of RSS channels. - * It does not set up any buffers, descriptor rings or event queues. - */ -static int falcon_init_nic(struct efx_nic *efx) +void efx_nic_init_common(struct efx_nic *efx) { efx_oword_t temp; - int rc; - - /* Use on-chip SRAM */ - efx_reado(efx, &temp, FR_AB_NIC_STAT); - EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); - efx_writeo(efx, &temp, FR_AB_NIC_STAT); - - /* Set the source of the GMAC clock */ - if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { - efx_reado(efx, &temp, FR_AB_GPIO_CTL); - EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); - 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; /* Set positions of descriptor caches in SRAM. */ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, @@ -3084,15 +3064,6 @@ static int falcon_init_nic(struct efx_nic *efx) FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); - /* Clear the parity enables on the TX data fifos as - * they produce false parity errors because of timing issues - */ - if (EFX_WORKAROUND_5129(efx)) { - efx_reado(efx, &temp, FR_AZ_CSR_SPARE); - EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); - efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); - } - /* Enable all the genuinely fatal interrupts. (They are still * masked by the overall interrupt mask, controlled by * falcon_interrupts()). @@ -3106,6 +3077,64 @@ static int falcon_init_nic(struct efx_nic *efx) EFX_INVERT_OWORD(temp); efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); + efx_setup_rss_indir_table(efx); + + /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be + * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. + */ + efx_reado(efx, &temp, FR_AZ_TX_RESERVED); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); + /* Enable SW_EV to inherit in char driver - assume harmless here */ + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); + /* Prefetch threshold 2 => fetch when descriptor cache half empty */ + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); + /* Squash TX of packets of 16 bytes or less */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); + efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); +} + +/* This call performs hardware-specific global initialisation, such as + * defining the descriptor cache sizes and number of RSS channels. + * It does not set up any buffers, descriptor rings or event queues. + */ +static int falcon_init_nic(struct efx_nic *efx) +{ + efx_oword_t temp; + int rc; + + /* Use on-chip SRAM */ + efx_reado(efx, &temp, FR_AB_NIC_STAT); + EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); + efx_writeo(efx, &temp, FR_AB_NIC_STAT); + + /* Set the source of the GMAC clock */ + if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { + efx_reado(efx, &temp, FR_AB_GPIO_CTL); + EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); + 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; + + /* Clear the parity enables on the TX data fifos as + * they produce false parity errors because of timing issues + */ + if (EFX_WORKAROUND_5129(efx)) { + efx_reado(efx, &temp, FR_AZ_CSR_SPARE); + EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); + efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); + } + if (EFX_WORKAROUND_7244(efx)) { efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); @@ -3115,8 +3144,6 @@ static int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); } - falcon_setup_rss_indir_table(efx); - /* XXX This is documented only for Falcon A0/A1 */ /* Setup RX. Wait for descriptor is broken and must * be disabled. RXDP recovery shouldn't be needed, but is. @@ -3128,24 +3155,6 @@ static int falcon_init_nic(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); efx_writeo(efx, &temp, FR_AA_RX_SELF_RST); - /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be - * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. - */ - efx_reado(efx, &temp, FR_AZ_TX_RESERVED); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); - /* Enable SW_EV to inherit in char driver - assume harmless here */ - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); - /* Prefetch threshold 2 => fetch when descriptor cache half empty */ - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); - /* Squash TX of packets of 16 bytes or less */ - if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) - EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); - efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); - /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 * descriptors (which is bad). */ @@ -3161,6 +3170,8 @@ static int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_BZ_DP_CTRL); } + efx_nic_init_common(efx); + return 0; } @@ -3178,7 +3189,7 @@ static void falcon_remove_nic(struct efx_nic *efx) memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); falcon_remove_spi_devices(efx); - falcon_free_buffer(efx, &efx->irq_status); + efx_nic_free_buffer(efx, &efx->irq_status); falcon_reset_hw(efx, RESET_TYPE_ALL); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 464c2747260..875b58e94e8 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -30,6 +30,14 @@ static inline int efx_nic_rev(struct efx_nic *efx) return efx->type->revision; } +extern u32 efx_nic_fpga_ver(struct efx_nic *efx); + +/* NIC has two interlinked PCI functions for the same port. */ +static inline bool efx_nic_is_dual_func(struct efx_nic *efx) +{ + return efx_nic_rev(efx) < EFX_REV_FALCON_B0; +} + /** * struct falcon_board_type - board operations and type information * @id: Board type id, as found in NVRAM @@ -108,49 +116,65 @@ extern struct efx_nic_type falcon_b0_nic_type; extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); /* TX data path */ -extern int falcon_probe_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); +extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); /* RX data path */ -extern int falcon_probe_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); +extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); /* Event data path */ -extern int falcon_probe_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); -extern void falcon_eventq_read_ack(struct efx_channel *channel); +extern int efx_nic_probe_eventq(struct efx_channel *channel); +extern void efx_nic_init_eventq(struct efx_channel *channel); +extern void efx_nic_fini_eventq(struct efx_channel *channel); +extern void efx_nic_remove_eventq(struct efx_channel *channel); +extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); +extern void efx_nic_eventq_read_ack(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); +extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; /* Interrupts and test events */ -extern int falcon_init_interrupt(struct efx_nic *efx); -extern void falcon_enable_interrupts(struct efx_nic *efx); -extern void falcon_generate_test_event(struct efx_channel *channel, - unsigned int magic); -extern void falcon_generate_interrupt(struct efx_nic *efx); -extern void falcon_disable_interrupts(struct efx_nic *efx); -extern void falcon_fini_interrupt(struct efx_nic *efx); - -#define FALCON_IRQ_MOD_RESOLUTION 5 +extern int efx_nic_init_interrupt(struct efx_nic *efx); +extern void efx_nic_enable_interrupts(struct efx_nic *efx); +extern void efx_nic_generate_test_event(struct efx_channel *channel, + unsigned int magic); +extern void efx_nic_generate_interrupt(struct efx_nic *efx); +extern void efx_nic_disable_interrupts(struct efx_nic *efx); +extern void efx_nic_fini_interrupt(struct efx_nic *efx); +extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); +extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); +extern void falcon_irq_ack_a1(struct efx_nic *efx); + +#define EFX_IRQ_MOD_RESOLUTION 5 /* Global Resources */ -extern int falcon_flush_queues(struct efx_nic *efx); +extern int efx_nic_flush_queues(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 int falcon_reset_xaui(struct efx_nic *efx); +extern void efx_nic_init_common(struct efx_nic *efx); + +int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, + unsigned int len); +void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); /* Tests */ +struct efx_nic_register_test { + unsigned address; + efx_oword_t mask; +}; +extern int efx_nic_test_registers(struct efx_nic *efx, + const struct efx_nic_register_test *regs, + size_t n_regs); /************************************************************************** * @@ -186,8 +210,8 @@ extern int falcon_reset_xaui(struct efx_nic *efx); #define MAC_DATA_LBN 0 #define MAC_DATA_WIDTH 32 -extern void falcon_generate_event(struct efx_channel *channel, - efx_qword_t *event); +extern void efx_nic_generate_event(struct efx_channel *channel, + efx_qword_t *event); extern void falcon_poll_xmac(struct efx_nic *efx); diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index accf055ff89..8fffd379294 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -341,7 +341,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, out: /* Send write pointer to card. */ - falcon_notify_rx_desc(rx_queue); + efx_nic_notify_rx_desc(rx_queue); /* If the fast fill is running inside from the refill tasklet, then * for SMP systems it may be running on a different CPU to @@ -640,7 +640,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) if (!rx_queue->buffer) return -ENOMEM; - rc = falcon_probe_rx(rx_queue); + rc = efx_nic_probe_rx(rx_queue); if (rc) { kfree(rx_queue->buffer); rx_queue->buffer = NULL; @@ -671,7 +671,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ - falcon_init_rx(rx_queue); + efx_nic_init_rx(rx_queue); } void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) @@ -681,7 +681,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue); - falcon_fini_rx(rx_queue); + efx_nic_fini_rx(rx_queue); /* Release RX buffers NB start at index 0 not current HW ptr */ if (rx_queue->buffer) { @@ -706,7 +706,7 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) { EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue); - falcon_remove_rx(rx_queue); + efx_nic_remove_rx(rx_queue); kfree(rx_queue->buffer); rx_queue->buffer = NULL; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index fa56e2e8e9c..9a240536deb 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -164,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx, goto success; } - falcon_generate_interrupt(efx); + efx_nic_generate_interrupt(efx); /* Wait for arrival of test interrupt. */ EFX_LOG(efx, "waiting for test interrupt\n"); @@ -202,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, channel->eventq_magic = 0; smp_wmb(); - falcon_generate_test_event(channel, magic); + efx_nic_generate_test_event(channel, magic); /* Wait for arrival of interrupt */ count = 0; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index c54fa30e627..2531d0207b9 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -278,7 +278,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) buffer->continuation = false; /* Pass off to hardware */ - falcon_push_buffers(tx_queue); + efx_nic_push_buffers(tx_queue); return NETDEV_TX_OK; @@ -426,7 +426,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) tx_queue->buffer[i].continuation = true; /* Allocate hardware ring */ - rc = falcon_probe_tx(tx_queue); + rc = efx_nic_probe_tx(tx_queue); if (rc) goto fail; @@ -449,7 +449,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) BUG_ON(tx_queue->stopped); /* Set up TX descriptor ring */ - falcon_init_tx(tx_queue); + efx_nic_init_tx(tx_queue); } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) @@ -475,7 +475,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue); /* Flush TX queue, remove descriptor ring */ - falcon_fini_tx(tx_queue); + efx_nic_fini_tx(tx_queue); efx_release_tx_buffers(tx_queue); @@ -492,7 +492,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) { EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue); - falcon_remove_tx(tx_queue); + efx_nic_remove_tx(tx_queue); kfree(tx_queue->buffer); tx_queue->buffer = NULL; @@ -1078,7 +1078,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, } /* Pass off to hardware */ - falcon_push_buffers(tx_queue); + efx_nic_push_buffers(tx_queue); tx_queue->tso_bursts++; return NETDEV_TX_OK; -- cgit v1.2.3-70-g09d2 From e58f69f4082f60076885798fae8f3a17ea713bf6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:08:41 +0000 Subject: sfc: Extend loopback mode enumeration New NICs and PHYs support a wider variety of loopback modes. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 19 +++++++- drivers/net/sfc/enum.h | 106 ++++++++++++++++++++++++++++++++++-------- drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/mdio_10g.c | 4 +- drivers/net/sfc/net_driver.h | 2 +- drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/tenxpress.c | 4 +- 7 files changed, 111 insertions(+), 28 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index e5c33c66eda..75dcaaedc3e 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -36,15 +36,32 @@ const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; const char *efx_loopback_mode_names[] = { [LOOPBACK_NONE] = "NONE", + [LOOPBACK_DATA] = "DATAPATH", [LOOPBACK_GMAC] = "GMAC", [LOOPBACK_XGMII] = "XGMII", [LOOPBACK_XGXS] = "XGXS", [LOOPBACK_XAUI] = "XAUI", + [LOOPBACK_GMII] = "GMII", + [LOOPBACK_SGMII] = "SGMII", + [LOOPBACK_XGBR] = "XGBR", + [LOOPBACK_XFI] = "XFI", + [LOOPBACK_XAUI_FAR] = "XAUI_FAR", + [LOOPBACK_GMII_FAR] = "GMII_FAR", + [LOOPBACK_SGMII_FAR] = "SGMII_FAR", + [LOOPBACK_XFI_FAR] = "XFI_FAR", [LOOPBACK_GPHY] = "GPHY", [LOOPBACK_PHYXS] = "PHYXS", [LOOPBACK_PCS] = "PCS", [LOOPBACK_PMAPMD] = "PMA/PMD", - [LOOPBACK_NETWORK] = "NETWORK", + [LOOPBACK_XPORT] = "XPORT", + [LOOPBACK_XGMII_WS] = "XGMII_WS", + [LOOPBACK_XAUI_WS] = "XAUI_WS", + [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", + [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", + [LOOPBACK_GMII_WS] = "GMII_WS", + [LOOPBACK_XFI_WS] = "XFI_WS", + [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", + [LOOPBACK_PHYXS_WS] = "PHYXS_WS", }; /* Interrupt mode names (see INT_MODE())) */ diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index fcd14b73f24..7a9e79ab931 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -13,38 +13,101 @@ /** * enum efx_loopback_mode - loopback modes * @LOOPBACK_NONE: no loopback - * @LOOPBACK_GMAC: loopback within GMAC at unspecified level - * @LOOPBACK_XGMII: loopback within XMAC at XGMII level - * @LOOPBACK_XGXS: loopback within XMAC at XGXS level - * @LOOPBACK_XAUI: loopback within XMAC at XAUI level + * @LOOPBACK_DATA: data path loopback + * @LOOPBACK_GMAC: loopback within GMAC + * @LOOPBACK_XGMII: loopback after XMAC + * @LOOPBACK_XGXS: loopback within BPX after XGXS + * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes + * @LOOPBACK_GMII: loopback within BPX after GMAC + * @LOOPBACK_SGMII: loopback within BPX within SGMII + * @LOOPBACK_XGBR: loopback within BPX within XGBR + * @LOOPBACK_XFI: loopback within BPX before XFI serdes + * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes + * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII + * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII + * @LOOPBACK_XFI_FAR: loopback after XFI serdes * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level * @LOOPBACK_PCS: loopback within 10G PHY at PCS level * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level - * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) + * @LOOPBACK_XPORT: cross port loopback + * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC + * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes + * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes + * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes + * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC + * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes + * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes + * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level */ -/* Please keep in order and up-to-date w.r.t the following two #defines */ +/* Please keep up-to-date w.r.t the following two #defines */ enum efx_loopback_mode { LOOPBACK_NONE = 0, - LOOPBACK_GMAC = 1, - LOOPBACK_XGMII = 2, - LOOPBACK_XGXS = 3, - LOOPBACK_XAUI = 4, - LOOPBACK_GPHY = 5, - LOOPBACK_PHYXS = 6, - LOOPBACK_PCS = 7, - LOOPBACK_PMAPMD = 8, - LOOPBACK_NETWORK = 9, + LOOPBACK_DATA = 1, + LOOPBACK_GMAC = 2, + LOOPBACK_XGMII = 3, + LOOPBACK_XGXS = 4, + LOOPBACK_XAUI = 5, + LOOPBACK_GMII = 6, + LOOPBACK_SGMII = 7, + LOOPBACK_XGBR = 8, + LOOPBACK_XFI = 9, + LOOPBACK_XAUI_FAR = 10, + LOOPBACK_GMII_FAR = 11, + LOOPBACK_SGMII_FAR = 12, + LOOPBACK_XFI_FAR = 13, + LOOPBACK_GPHY = 14, + LOOPBACK_PHYXS = 15, + LOOPBACK_PCS = 16, + LOOPBACK_PMAPMD = 17, + LOOPBACK_XPORT = 18, + LOOPBACK_XGMII_WS = 19, + LOOPBACK_XAUI_WS = 20, + LOOPBACK_XAUI_WS_FAR = 21, + LOOPBACK_XAUI_WS_NEAR = 22, + LOOPBACK_GMII_WS = 23, + LOOPBACK_XFI_WS = 24, + LOOPBACK_XFI_WS_FAR = 25, + LOOPBACK_PHYXS_WS = 26, LOOPBACK_MAX }; - #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD /* These loopbacks occur within the controller */ -#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ - (1 << LOOPBACK_XGMII)| \ - (1 << LOOPBACK_XGXS) | \ - (1 << LOOPBACK_XAUI)) +#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \ + (1 << LOOPBACK_GMAC) | \ + (1 << LOOPBACK_XGMII)| \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI) | \ + (1 << LOOPBACK_GMII) | \ + (1 << LOOPBACK_SGMII) | \ + (1 << LOOPBACK_SGMII) | \ + (1 << LOOPBACK_XGBR) | \ + (1 << LOOPBACK_XFI) | \ + (1 << LOOPBACK_XAUI_FAR) | \ + (1 << LOOPBACK_GMII_FAR) | \ + (1 << LOOPBACK_SGMII_FAR) | \ + (1 << LOOPBACK_XFI_FAR) | \ + (1 << LOOPBACK_XGMII_WS) | \ + (1 << LOOPBACK_XAUI_WS) | \ + (1 << LOOPBACK_XAUI_WS_FAR) | \ + (1 << LOOPBACK_XAUI_WS_NEAR) | \ + (1 << LOOPBACK_GMII_WS) | \ + (1 << LOOPBACK_XFI_WS) | \ + (1 << LOOPBACK_XFI_WS_FAR)) + +#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \ + (1 << LOOPBACK_XAUI_WS) | \ + (1 << LOOPBACK_XAUI_WS_FAR) | \ + (1 << LOOPBACK_XAUI_WS_NEAR) | \ + (1 << LOOPBACK_GMII_WS) | \ + (1 << LOOPBACK_XFI_WS) | \ + (1 << LOOPBACK_XFI_WS_FAR) | \ + (1 << LOOPBACK_PHYXS_WS)) + +#define LOOPBACKS_EXTERNAL(_efx) \ + ((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \ + ~(1 << LOOPBACK_NONE)) #define LOOPBACK_MASK(_efx) \ (1 << (_efx)->loopback_mode) @@ -52,6 +115,9 @@ enum efx_loopback_mode { #define LOOPBACK_INTERNAL(_efx) \ (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) +#define LOOPBACK_EXTERNAL(_efx) \ + (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx))) + #define LOOPBACK_CHANGED(_from, _to, _mask) \ (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 898afc1b5ef..83da79279a9 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -249,7 +249,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { bool mac_up = falcon_xaui_link_ok(efx); - if ((efx->loopback_mode == LOOPBACK_NETWORK) || + if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || efx_phy_mode_disabled(efx->phy_mode)) /* XAUI link is expected to be down */ return mac_up; diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 1f62a5c002f..e6ca988abbb 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -173,7 +173,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) * of mmd's */ if (LOOPBACK_INTERNAL(efx)) return true; - else if (efx->loopback_mode == LOOPBACK_NETWORK) + else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS) return false; else if (efx_phy_mode_disabled(efx->phy_mode)) return false; @@ -210,7 +210,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx) efx->loopback_mode == LOOPBACK_PCS); efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, - efx->loopback_mode == LOOPBACK_NETWORK); + efx->loopback_mode == LOOPBACK_PHYXS_WS); } static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 62b2089b05d..cd2debb0a55 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -824,7 +824,7 @@ struct efx_nic { atomic_t rx_reset; enum efx_loopback_mode loopback_mode; - unsigned int loopback_modes; + u64 loopback_modes; void *loopback_selftest; }; diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 4c38516a552..49a5ab5efb9 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -23,7 +23,7 @@ #define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) /****************************************************************************/ /* Quake-specific MDIO registers */ diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index c30185393cd..0dfb2275a15 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -30,13 +30,13 @@ #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) #define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ (1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) /* We complain if we fail to see the link partner as 10G capable this many * times in a row (must be > 1 as sampling the autoneg. registers is racy) -- cgit v1.2.3-70-g09d2 From 76884835684411264cda2f15585261eb02183541 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:10:44 +0000 Subject: sfc: Extend MTD driver for use with new NICs In new NICs flash is managed by firmware and we will use high-level operations on partitions rather than direct SPI commands. Add support for multiple MTD partitions per flash device and remove the direct link between MTD and SPI devices. Maintain a list of MTD partitions in struct efx_nic. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 3 + drivers/net/sfc/ethtool.c | 6 +- drivers/net/sfc/falcon.c | 32 +++-- drivers/net/sfc/mtd.c | 312 ++++++++++++++++++++++++++++++------------- drivers/net/sfc/net_driver.h | 8 +- drivers/net/sfc/spi.h | 18 ++- 6 files changed, 255 insertions(+), 124 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 75dcaaedc3e..4fe6d635ef3 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1977,6 +1977,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, spin_lock_init(&efx->biu_lock); mutex_init(&efx->mdio_lock); mutex_init(&efx->spi_lock); +#ifdef CONFIG_SFC_MTD + INIT_LIST_HEAD(&efx->mtd_list); +#endif INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); efx->pci_dev = pci_dev; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 4fe874052e3..08a9db99374 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -567,7 +567,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + rc = falcon_spi_read(efx, spi, + eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); mutex_unlock(&efx->spi_lock); @@ -590,7 +591,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + rc = falcon_spi_write(efx, spi, + eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); mutex_unlock(&efx->spi_lock); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 29d45376e4c..950de847d22 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1640,11 +1640,10 @@ static int falcon_spi_wait(struct efx_nic *efx) } } -int falcon_spi_cmd(const struct efx_spi_device *spi, +int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, unsigned int command, int address, const void *in, void *out, size_t len) { - struct efx_nic *efx = spi->efx; bool addressed = (address >= 0); bool reading = (out != NULL); efx_oword_t reg; @@ -1713,15 +1712,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi, } /* Wait up to 10 ms for buffered write completion */ -int falcon_spi_wait_write(const struct efx_spi_device *spi) +int +falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) { - struct efx_nic *efx = spi->efx; unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); u8 status; int rc; for (;;) { - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; @@ -1737,8 +1736,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi) } } -int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, u8 *buffer) +int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, u8 *buffer) { size_t block_len, pos = 0; unsigned int command; @@ -1748,7 +1747,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, block_len = min(len - pos, FALCON_SPI_MAX_LEN); command = efx_spi_munge_command(spi, SPI_READ, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, NULL, + rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, buffer + pos, block_len); if (rc) break; @@ -1767,8 +1766,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, return rc; } -int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, const u8 *buffer) +int +falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, const u8 *buffer) { u8 verify_buffer[FALCON_SPI_MAX_LEN]; size_t block_len, pos = 0; @@ -1776,24 +1776,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, int rc = 0; while (pos < len) { - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) break; block_len = min(len - pos, falcon_spi_write_limit(spi, start + pos)); command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, + rc = falcon_spi_cmd(efx, spi, command, start + pos, buffer + pos, NULL, block_len); if (rc) break; - rc = falcon_spi_wait_write(spi); + rc = falcon_spi_wait_write(efx, spi); if (rc) break; command = efx_spi_munge_command(spi, SPI_READ, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, + rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, verify_buffer, block_len); if (memcmp(verify_buffer, buffer + pos, block_len)) { rc = -EIO; @@ -2352,7 +2352,7 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) nvconfig = region + FALCON_NVCONFIG_OFFSET; mutex_lock(&efx->spi_lock); - rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); + rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); mutex_unlock(&efx->spi_lock); if (rc) { EFX_ERR(efx, "Failed to read %s\n", @@ -2710,8 +2710,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, spi_device->block_size = 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_BLOCK_SIZE); - - spi_device->efx = efx; } else { spi_device = NULL; } diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 820c233c3ea..3121e242d82 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -11,26 +11,58 @@ #include #include #include +#include #define EFX_DRIVER_NAME "sfc_mtd" #include "net_driver.h" #include "spi.h" #include "efx.h" +#include "falcon.h" #define EFX_SPI_VERIFY_BUF_LEN 16 -struct efx_mtd { - const struct efx_spi_device *spi; +struct efx_mtd_partition { struct mtd_info mtd; + size_t offset; + const char *type_name; char name[IFNAMSIZ + 20]; }; +struct efx_mtd_ops { + int (*read)(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, u8 *buffer); + int (*erase)(struct mtd_info *mtd, loff_t start, size_t len); + int (*write)(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, const u8 *buffer); + int (*sync)(struct mtd_info *mtd); +}; + +struct efx_mtd { + struct list_head node; + struct efx_nic *efx; + const struct efx_spi_device *spi; + const char *name; + const struct efx_mtd_ops *ops; + size_t n_parts; + struct efx_mtd_partition part[0]; +}; + +#define efx_for_each_partition(part, efx_mtd) \ + for ((part) = &(efx_mtd)->part[0]; \ + (part) != &(efx_mtd)->part[(efx_mtd)->n_parts]; \ + (part)++) + +#define to_efx_mtd_partition(mtd) \ + container_of(mtd, struct efx_mtd_partition, mtd) + +static int falcon_mtd_probe(struct efx_nic *efx); + /* SPI utilities */ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) { const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; u8 status; int rc, i; @@ -39,7 +71,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) __set_current_state(uninterruptible ? TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; @@ -52,32 +84,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) return -ETIMEDOUT; } -static int efx_spi_unlock(const struct efx_spi_device *spi) +static int +efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi) { const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | SPI_STATUS_BP0); u8 status; int rc; - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); if (rc) return rc; if (!(status & unlock_mask)) return 0; /* already unlocked */ - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) return rc; - rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); if (rc) return rc; status &= ~unlock_mask; - rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); + rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, + NULL, sizeof(status)); if (rc) return rc; - rc = falcon_spi_wait_write(spi); + rc = falcon_spi_wait_write(efx, spi); if (rc) return rc; @@ -87,6 +122,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) { const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = efx_mtd->efx; unsigned pos, block_len; u8 empty[EFX_SPI_VERIFY_BUF_LEN]; u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; @@ -98,13 +134,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) if (spi->erase_command == 0) return -EOPNOTSUPP; - rc = efx_spi_unlock(spi); + rc = efx_spi_unlock(efx, spi); if (rc) return rc; - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) return rc; - rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, + NULL, 0); if (rc) return rc; rc = efx_spi_slow_wait(efx_mtd, false); @@ -113,7 +150,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) memset(empty, 0xff, sizeof(empty)); for (pos = 0; pos < len; pos += block_len) { block_len = min(len - pos, sizeof(buffer)); - rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); + rc = falcon_spi_read(efx, spi, start + pos, block_len, + NULL, buffer); if (rc) return rc; if (memcmp(empty, buffer, block_len)) @@ -130,140 +168,228 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) /* MTD interface */ -static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, - size_t *retlen, u8 *buffer) +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + struct efx_mtd *efx_mtd = mtd->priv; + int rc; + + rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); + if (rc == 0) { + erase->state = MTD_ERASE_DONE; + } else { + erase->state = MTD_ERASE_FAILED; + erase->fail_addr = 0xffffffff; + } + mtd_erase_callback(erase); + return rc; +} + +static void efx_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + int rc; + + rc = efx_mtd->ops->sync(mtd); + if (rc) + EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); +} + +static void efx_mtd_remove_partition(struct efx_mtd_partition *part) +{ + int rc; + + for (;;) { + rc = del_mtd_device(&part->mtd); + if (rc != -EBUSY) + break; + ssleep(1); + } + WARN_ON(rc); +} + +static void efx_mtd_remove_device(struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_for_each_partition(part, efx_mtd) + efx_mtd_remove_partition(part); + list_del(&efx_mtd->node); + kfree(efx_mtd); +} + +static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_for_each_partition(part, efx_mtd) + snprintf(part->name, sizeof(part->name), + "%s %s", efx_mtd->efx->name, + part->type_name); +} + +static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_mtd->efx = efx; + + efx_mtd_rename_device(efx_mtd); + + efx_for_each_partition(part, efx_mtd) { + part->mtd.writesize = 1; + + part->mtd.owner = THIS_MODULE; + part->mtd.priv = efx_mtd; + part->mtd.name = part->name; + part->mtd.erase = efx_mtd_erase; + part->mtd.read = efx_mtd->ops->read; + part->mtd.write = efx_mtd->ops->write; + part->mtd.sync = efx_mtd_sync; + + if (add_mtd_device(&part->mtd)) + goto fail; + } + + list_add(&efx_mtd->node, &efx->mtd_list); + return 0; + +fail: + while (part != &efx_mtd->part[0]) { + --part; + efx_mtd_remove_partition(part); + } + /* add_mtd_device() returns 1 if the MTD table is full */ + return -ENOMEM; +} + +void efx_mtd_remove(struct efx_nic *efx) { + struct efx_mtd *efx_mtd, *next; + + WARN_ON(efx_dev_registered(efx)); + + list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node) + efx_mtd_remove_device(efx_mtd); +} + +void efx_mtd_rename(struct efx_nic *efx) +{ + struct efx_mtd *efx_mtd; + + ASSERT_RTNL(); + + list_for_each_entry(efx_mtd, &efx->mtd_list, node) + efx_mtd_rename_device(efx_mtd); +} + +int efx_mtd_probe(struct efx_nic *efx) +{ + return falcon_mtd_probe(efx); +} + +/* Implementation of MTD operations for Falcon */ + +static int falcon_mtd_read(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, u8 *buffer) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); struct efx_mtd *efx_mtd = mtd->priv; const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, - len, retlen, buffer); + rc = falcon_spi_read(efx, spi, part->offset + start, len, + retlen, buffer); mutex_unlock(&efx->spi_lock); return rc; } -static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) +static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) { + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); struct efx_mtd *efx_mtd = mtd->priv; - struct efx_nic *efx = efx_mtd->spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, - erase->len); + rc = efx_spi_erase(efx_mtd, part->offset + start, len); mutex_unlock(&efx->spi_lock); - - if (rc == 0) { - erase->state = MTD_ERASE_DONE; - } else { - erase->state = MTD_ERASE_FAILED; - erase->fail_addr = 0xffffffff; - } - mtd_erase_callback(erase); return rc; } -static int efx_mtd_write(struct mtd_info *mtd, loff_t start, - size_t len, size_t *retlen, const u8 *buffer) +static int falcon_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) { + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); struct efx_mtd *efx_mtd = mtd->priv; const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, - len, retlen, buffer); + rc = falcon_spi_write(efx, spi, part->offset + start, len, + retlen, buffer); mutex_unlock(&efx->spi_lock); return rc; } -static void efx_mtd_sync(struct mtd_info *mtd) +static int falcon_mtd_sync(struct mtd_info *mtd) { struct efx_mtd *efx_mtd = mtd->priv; - struct efx_nic *efx = efx_mtd->spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; mutex_lock(&efx->spi_lock); rc = efx_spi_slow_wait(efx_mtd, true); mutex_unlock(&efx->spi_lock); - - if (rc) - EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); - return; -} - -void efx_mtd_remove(struct efx_nic *efx) -{ - if (efx->spi_flash && efx->spi_flash->mtd) { - struct efx_mtd *efx_mtd = efx->spi_flash->mtd; - int rc; - - for (;;) { - rc = del_mtd_device(&efx_mtd->mtd); - if (rc != -EBUSY) - break; - ssleep(1); - } - WARN_ON(rc); - kfree(efx_mtd); - } + return rc; } -void efx_mtd_rename(struct efx_nic *efx) -{ - if (efx->spi_flash && efx->spi_flash->mtd) { - struct efx_mtd *efx_mtd = efx->spi_flash->mtd; - snprintf(efx_mtd->name, sizeof(efx_mtd->name), - "%s sfc_flash_bootrom", efx->name); - } -} +static struct efx_mtd_ops falcon_mtd_ops = { + .read = falcon_mtd_read, + .erase = falcon_mtd_erase, + .write = falcon_mtd_write, + .sync = falcon_mtd_sync, +}; -int efx_mtd_probe(struct efx_nic *efx) +static int falcon_mtd_probe(struct efx_nic *efx) { struct efx_spi_device *spi = efx->spi_flash; struct efx_mtd *efx_mtd; + int rc; + + ASSERT_RTNL(); if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) return -ENODEV; - efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); + efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]), + GFP_KERNEL); if (!efx_mtd) return -ENOMEM; efx_mtd->spi = spi; - spi->mtd = efx_mtd; - - efx_mtd->mtd.type = MTD_NORFLASH; - efx_mtd->mtd.flags = MTD_CAP_NORFLASH; - efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; - efx_mtd->mtd.erasesize = spi->erase_size; - efx_mtd->mtd.writesize = 1; - efx_mtd_rename(efx); - - efx_mtd->mtd.owner = THIS_MODULE; - efx_mtd->mtd.priv = efx_mtd; - efx_mtd->mtd.name = efx_mtd->name; - efx_mtd->mtd.erase = efx_mtd_erase; - efx_mtd->mtd.read = efx_mtd_read; - efx_mtd->mtd.write = efx_mtd_write; - efx_mtd->mtd.sync = efx_mtd_sync; - - if (add_mtd_device(&efx_mtd->mtd)) { + efx_mtd->name = "flash"; + efx_mtd->ops = &falcon_mtd_ops; + + efx_mtd->n_parts = 1; + efx_mtd->part[0].mtd.type = MTD_NORFLASH; + efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH; + efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; + efx_mtd->part[0].mtd.erasesize = spi->erase_size; + efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START; + efx_mtd->part[0].type_name = "sfc_flash_bootrom"; + + rc = efx_mtd_probe_device(efx, efx_mtd); + if (rc) kfree(efx_mtd); - spi->mtd = NULL; - /* add_mtd_device() returns 1 if the MTD table is full */ - return -ENOMEM; - } - - return 0; + return rc; } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 452f83510b0..e1534ba6ad7 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -674,10 +674,11 @@ union efx_multicast_hash { * interrupt is handled. It is used by falcon_test_interrupt() * to verify that an interrupt has occurred. * @spi_flash: SPI flash device - * This field will be %NULL if no flash device is present. + * This field will be %NULL if no flash device is present (or for Siena). * @spi_eeprom: SPI EEPROM device - * This field will be %NULL if no EEPROM device is present. + * This field will be %NULL if no EEPROM device is present (or for Siena). * @spi_lock: SPI bus lock + * @mtd_list: List of MTDs attached to the NIC * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, @@ -759,6 +760,9 @@ struct efx_nic { struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; struct mutex spi_lock; +#ifdef CONFIG_SFC_MTD + struct list_head mtd_list; +#endif unsigned n_rx_nodesc_drop_cnt; diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 1b1ceb41167..8bf4fce0813 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -36,8 +36,6 @@ /** * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device - * @efx: The Efx controller that owns this device - * @mtd: MTD state * @device_id: Controller's id for the device * @size: Size (in bytes) * @addr_len: Number of address bytes in read/write commands @@ -54,10 +52,6 @@ * Write commands are limited to blocks with this size and alignment. */ struct efx_spi_device { - struct efx_nic *efx; -#ifdef CONFIG_SFC_MTD - void *mtd; -#endif int device_id; unsigned int size; unsigned int addr_len; @@ -67,12 +61,16 @@ struct efx_spi_device { unsigned int block_size; }; -int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, +int falcon_spi_cmd(struct efx_nic *efx, + const struct efx_spi_device *spi, unsigned int command, int address, const void* in, void *out, size_t len); -int falcon_spi_wait_write(const struct efx_spi_device *spi); -int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, +int falcon_spi_wait_write(struct efx_nic *efx, + const struct efx_spi_device *spi); +int falcon_spi_read(struct efx_nic *efx, + const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer); -int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, +int falcon_spi_write(struct efx_nic *efx, + const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer); /* -- cgit v1.2.3-70-g09d2 From c383b53729a9bbbceee132a85955d084ba00ca3a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:11:02 +0000 Subject: sfc: Allow for additional checksum offload features Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/ethtool.c | 16 +++++++++++++++- drivers/net/sfc/falcon.c | 2 ++ drivers/net/sfc/net_driver.h | 3 +++ 4 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4fe6d635ef3..c49d364ebdb 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2179,7 +2179,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, net_dev = alloc_etherdev(sizeof(*efx)); if (!net_dev) return -ENOMEM; - net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | + net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_GRO); /* Mask for features that also apply to VLAN devices */ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 08a9db99374..0a79ec7d45e 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -468,6 +468,19 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } +static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx = netdev_priv(net_dev); + unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; + + if (enable) + net_dev->features |= features; + else + net_dev->features &= ~features; + + return 0; +} + static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) { struct efx_nic *efx = netdev_priv(net_dev); @@ -813,7 +826,8 @@ const struct ethtool_ops efx_ethtool_ops = { .get_rx_csum = efx_ethtool_get_rx_csum, .set_rx_csum = efx_ethtool_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, + /* Need to enable/disable IPv6 too */ + .set_tx_csum = efx_ethtool_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 950de847d22..f77bbbeacb6 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -3304,6 +3304,7 @@ struct efx_nic_type falcon_a1_nic_type = { .phys_addr_channels = 4, .tx_dc_base = 0x130000, .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM, .reset_world_flags = ETH_RESET_IRQ, }; @@ -3351,6 +3352,7 @@ struct efx_nic_type falcon_b0_nic_type = { * channels */ .tx_dc_base = 0x130000, .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM, .reset_world_flags = ETH_RESET_IRQ, }; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e1534ba6ad7..96d3f00df64 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -864,6 +864,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * descriptors * @tx_dc_base: Base address in SRAM of TX queue descriptor caches * @rx_dc_base: Base address in SRAM of RX queue descriptor caches + * @offload_features: net_device feature flags for protocol offload + * features implemented in hardware * @reset_world_flags: Flags for additional components covered by * reset method RESET_TYPE_WORLD */ @@ -904,6 +906,7 @@ struct efx_nic_type { unsigned int phys_addr_channels; unsigned int tx_dc_base; unsigned int rx_dc_base; + unsigned long offload_features; u32 reset_world_flags; }; -- cgit v1.2.3-70-g09d2 From 744093c98363f8a65853aed39708c9effc80f8ff Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:12:08 +0000 Subject: sfc: Rename falcon.h to nic.h nic.h is no longer specific to Falcon. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/falcon.h | 238 ---------------------------------------- drivers/net/sfc/falcon_boards.c | 2 +- drivers/net/sfc/falcon_gmac.c | 2 +- drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/mdio_10g.c | 2 +- drivers/net/sfc/mtd.c | 2 +- drivers/net/sfc/nic.h | 238 ++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/rx.c | 2 +- drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/tenxpress.c | 2 +- drivers/net/sfc/tx.c | 2 +- 15 files changed, 251 insertions(+), 251 deletions(-) delete mode 100644 drivers/net/sfc/falcon.h create mode 100644 drivers/net/sfc/nic.h (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index c49d364ebdb..97a6ebdcaf2 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -23,7 +23,7 @@ #include "net_driver.h" #include "efx.h" #include "mdio_10g.h" -#include "falcon.h" +#include "nic.h" /************************************************************************** * diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 0a79ec7d45e..012ee31db0c 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -15,7 +15,7 @@ #include "workarounds.h" #include "selftest.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "spi.h" #include "mdio_10g.h" diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index f77bbbeacb6..64b47da1232 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -20,7 +20,7 @@ #include "efx.h" #include "mac.h" #include "spi.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "mdio_10g.h" diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h deleted file mode 100644 index 3085ecfacee..00000000000 --- a/drivers/net/sfc/falcon.h +++ /dev/null @@ -1,238 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_FALCON_H -#define EFX_FALCON_H - -#include -#include "net_driver.h" -#include "efx.h" - -/* - * Falcon hardware control - */ - -enum { - EFX_REV_FALCON_A0 = 0, - EFX_REV_FALCON_A1 = 1, - EFX_REV_FALCON_B0 = 2, -}; - -static inline int efx_nic_rev(struct efx_nic *efx) -{ - return efx->type->revision; -} - -extern u32 efx_nic_fpga_ver(struct efx_nic *efx); - -/* NIC has two interlinked PCI functions for the same port. */ -static inline bool efx_nic_is_dual_func(struct efx_nic *efx) -{ - return efx_nic_rev(efx) < EFX_REV_FALCON_B0; -} - -enum { - PHY_TYPE_NONE = 0, - PHY_TYPE_TXC43128 = 1, - PHY_TYPE_88E1111 = 2, - PHY_TYPE_SFX7101 = 3, - PHY_TYPE_QT2022C2 = 4, - PHY_TYPE_PM8358 = 6, - PHY_TYPE_SFT9001A = 8, - PHY_TYPE_QT2025C = 9, - PHY_TYPE_SFT9001B = 10, -}; - -#define FALCON_XMAC_LOOPBACKS \ - ((1 << LOOPBACK_XGMII) | \ - (1 << LOOPBACK_XGXS) | \ - (1 << LOOPBACK_XAUI)) - -#define FALCON_GMAC_LOOPBACKS \ - (1 << LOOPBACK_GMAC) - -/** - * 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 - */ -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 { - const struct falcon_board_type *type; - int major; - int minor; - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_data; - struct i2c_client *hwmon_client, *ioexp_client; -}; - -/** - * 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) -{ - struct falcon_nic_data *data = efx->nic_data; - return &data->board; -} - -extern struct efx_nic_type falcon_a1_nic_type; -extern struct efx_nic_type falcon_b0_nic_type; - -/************************************************************************** - * - * Externs - * - ************************************************************************** - */ - -extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); - -/* TX data path */ -extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); -extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); -extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); -extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); -extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); - -/* RX data path */ -extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); -extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); -extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); -extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); -extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); - -/* Event data path */ -extern int efx_nic_probe_eventq(struct efx_channel *channel); -extern void efx_nic_init_eventq(struct efx_channel *channel); -extern void efx_nic_fini_eventq(struct efx_channel *channel); -extern void efx_nic_remove_eventq(struct efx_channel *channel); -extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); -extern void efx_nic_eventq_read_ack(struct efx_channel *channel); - -/* MAC/PHY */ -extern void falcon_drain_tx_fifo(struct efx_nic *efx); -extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); -extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; - -/* Interrupts and test events */ -extern int efx_nic_init_interrupt(struct efx_nic *efx); -extern void efx_nic_enable_interrupts(struct efx_nic *efx); -extern void efx_nic_generate_test_event(struct efx_channel *channel, - unsigned int magic); -extern void efx_nic_generate_interrupt(struct efx_nic *efx); -extern void efx_nic_disable_interrupts(struct efx_nic *efx); -extern void efx_nic_fini_interrupt(struct efx_nic *efx); -extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); -extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); -extern void falcon_irq_ack_a1(struct efx_nic *efx); - -#define EFX_IRQ_MOD_RESOLUTION 5 - -/* Global Resources */ -extern int efx_nic_flush_queues(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 int falcon_reset_xaui(struct efx_nic *efx); -extern void efx_nic_init_common(struct efx_nic *efx); - -int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, - unsigned int len); -void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); - -/* Tests */ -struct efx_nic_register_test { - unsigned address; - efx_oword_t mask; -}; -extern int efx_nic_test_registers(struct efx_nic *efx, - const struct efx_nic_register_test *regs, - size_t n_regs); - -/************************************************************************** - * - * Falcon MAC stats - * - ************************************************************************** - */ - -#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) -#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) - -/* Retrieve statistic from statistics block */ -#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ - if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ - (efx)->mac_stats.efx_stat += le16_to_cpu( \ - *((__force __le16 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ - (efx)->mac_stats.efx_stat += le32_to_cpu( \ - *((__force __le32 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - else \ - (efx)->mac_stats.efx_stat += le64_to_cpu( \ - *((__force __le64 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - } while (0) - -#define FALCON_MAC_STATS_SIZE 0x100 - -#define MAC_DATA_LBN 0 -#define MAC_DATA_WIDTH 32 - -extern void efx_nic_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 b92decc9521..fa4d4c72ccd 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -12,7 +12,7 @@ #include "net_driver.h" #include "phy.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "workarounds.h" diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index 19dd3ac3d1c..aa9b689cadc 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c @@ -11,7 +11,7 @@ #include #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "mac.h" #include "regs.h" #include "io.h" diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 643622df6e6..cd63f242698 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -11,7 +11,7 @@ #include #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "mac.h" diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 20e627431d2..19496da3e2b 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -15,7 +15,7 @@ #include "net_driver.h" #include "mdio_10g.h" #include "workarounds.h" -#include "falcon.h" +#include "nic.h" unsigned efx_mdio_id_oui(u32 id) { diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 3121e242d82..65a22f193f9 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -17,7 +17,7 @@ #include "net_driver.h" #include "spi.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #define EFX_SPI_VERIFY_BUF_LEN 16 diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h new file mode 100644 index 00000000000..e7eb30488c1 --- /dev/null +++ b/drivers/net/sfc/nic.h @@ -0,0 +1,238 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2008 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_NIC_H +#define EFX_NIC_H + +#include +#include "net_driver.h" +#include "efx.h" + +/* + * Falcon hardware control + */ + +enum { + EFX_REV_FALCON_A0 = 0, + EFX_REV_FALCON_A1 = 1, + EFX_REV_FALCON_B0 = 2, +}; + +static inline int efx_nic_rev(struct efx_nic *efx) +{ + return efx->type->revision; +} + +extern u32 efx_nic_fpga_ver(struct efx_nic *efx); + +/* NIC has two interlinked PCI functions for the same port. */ +static inline bool efx_nic_is_dual_func(struct efx_nic *efx) +{ + return efx_nic_rev(efx) < EFX_REV_FALCON_B0; +} + +enum { + PHY_TYPE_NONE = 0, + PHY_TYPE_TXC43128 = 1, + PHY_TYPE_88E1111 = 2, + PHY_TYPE_SFX7101 = 3, + PHY_TYPE_QT2022C2 = 4, + PHY_TYPE_PM8358 = 6, + PHY_TYPE_SFT9001A = 8, + PHY_TYPE_QT2025C = 9, + PHY_TYPE_SFT9001B = 10, +}; + +#define FALCON_XMAC_LOOPBACKS \ + ((1 << LOOPBACK_XGMII) | \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI)) + +#define FALCON_GMAC_LOOPBACKS \ + (1 << LOOPBACK_GMAC) + +/** + * 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 + */ +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 { + const struct falcon_board_type *type; + int major; + int minor; + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_data; + struct i2c_client *hwmon_client, *ioexp_client; +}; + +/** + * 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) +{ + struct falcon_nic_data *data = efx->nic_data; + return &data->board; +} + +extern struct efx_nic_type falcon_a1_nic_type; +extern struct efx_nic_type falcon_b0_nic_type; + +/************************************************************************** + * + * Externs + * + ************************************************************************** + */ + +extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); + +/* TX data path */ +extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); + +/* RX data path */ +extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); + +/* Event data path */ +extern int efx_nic_probe_eventq(struct efx_channel *channel); +extern void efx_nic_init_eventq(struct efx_channel *channel); +extern void efx_nic_fini_eventq(struct efx_channel *channel); +extern void efx_nic_remove_eventq(struct efx_channel *channel); +extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); +extern void efx_nic_eventq_read_ack(struct efx_channel *channel); + +/* MAC/PHY */ +extern void falcon_drain_tx_fifo(struct efx_nic *efx); +extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); +extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; + +/* Interrupts and test events */ +extern int efx_nic_init_interrupt(struct efx_nic *efx); +extern void efx_nic_enable_interrupts(struct efx_nic *efx); +extern void efx_nic_generate_test_event(struct efx_channel *channel, + unsigned int magic); +extern void efx_nic_generate_interrupt(struct efx_nic *efx); +extern void efx_nic_disable_interrupts(struct efx_nic *efx); +extern void efx_nic_fini_interrupt(struct efx_nic *efx); +extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); +extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); +extern void falcon_irq_ack_a1(struct efx_nic *efx); + +#define EFX_IRQ_MOD_RESOLUTION 5 + +/* Global Resources */ +extern int efx_nic_flush_queues(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 int falcon_reset_xaui(struct efx_nic *efx); +extern void efx_nic_init_common(struct efx_nic *efx); + +int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, + unsigned int len); +void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); + +/* Tests */ +struct efx_nic_register_test { + unsigned address; + efx_oword_t mask; +}; +extern int efx_nic_test_registers(struct efx_nic *efx, + const struct efx_nic_register_test *regs, + size_t n_regs); + +/************************************************************************** + * + * Falcon MAC stats + * + ************************************************************************** + */ + +#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) +#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) + +/* Retrieve statistic from statistics block */ +#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ + if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ + (efx)->mac_stats.efx_stat += le16_to_cpu( \ + *((__force __le16 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ + (efx)->mac_stats.efx_stat += le32_to_cpu( \ + *((__force __le32 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + else \ + (efx)->mac_stats.efx_stat += le64_to_cpu( \ + *((__force __le64 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + } while (0) + +#define FALCON_MAC_STATS_SIZE 0x100 + +#define MAC_DATA_LBN 0 +#define MAC_DATA_WIDTH 32 + +extern void efx_nic_generate_event(struct efx_channel *channel, + efx_qword_t *event); + +extern void falcon_poll_xmac(struct efx_nic *efx); + +#endif /* EFX_NIC_H */ diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 22b0e89ba8f..957e534a179 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -15,7 +15,7 @@ #include "efx.h" #include "mdio_10g.h" #include "phy.h" -#include "falcon.h" +#include "nic.h" #define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS | \ MDIO_DEVS_PMAPMD | \ diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 8fffd379294..03eace323d3 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -17,7 +17,7 @@ #include #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "selftest.h" #include "workarounds.h" diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 16258d83b70..1635f575112 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -21,7 +21,7 @@ #include #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "selftest.h" #include "workarounds.h" #include "spi.h" diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 8de97a9f271..ff97133c2b9 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -12,7 +12,7 @@ #include #include "efx.h" #include "mdio_10g.h" -#include "falcon.h" +#include "nic.h" #include "phy.h" #include "regs.h" #include "workarounds.h" diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 2531d0207b9..389ede43e34 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -16,7 +16,7 @@ #include #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "workarounds.h" /* -- cgit v1.2.3-70-g09d2 From 8880f4ec21e668dcab3c6d387524a887e5bcbf73 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:15:41 +0000 Subject: sfc: Add support for SFC9000 family (2) This integrates support for the SFC9000 family of 10G Ethernet controllers and LAN-on-motherboard chips, starting with the SFL9021 'Siena' and SFC9020 'Bethpage'. Credit for this code is largely due to my colleagues at Solarflare: Guido Barzini Steve Hodgson Kieran Mansley Matthew Slattery Neil Turton Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/Kconfig | 13 +- drivers/net/sfc/Makefile | 7 +- drivers/net/sfc/bitfield.h | 2 + drivers/net/sfc/efx.c | 26 ++++ drivers/net/sfc/efx.h | 2 + drivers/net/sfc/enum.h | 2 + drivers/net/sfc/ethtool.c | 3 + drivers/net/sfc/mac.h | 3 + drivers/net/sfc/mtd.c | 267 +++++++++++++++++++++++++++++++++++++++++- drivers/net/sfc/net_driver.h | 10 +- drivers/net/sfc/nic.c | 63 +++++++--- drivers/net/sfc/nic.h | 23 ++++ drivers/net/sfc/phy.h | 17 +++ drivers/net/sfc/workarounds.h | 5 + 14 files changed, 414 insertions(+), 29 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 260aafaac23..a65c9863839 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -1,5 +1,5 @@ config SFC - tristate "Solarflare Solarstorm SFC4000 support" + tristate "Solarflare Solarstorm SFC4000/SFC9000-family support" depends on PCI && INET select MDIO select CRC32 @@ -7,15 +7,16 @@ config SFC select I2C_ALGOBIT help This driver supports 10-gigabit Ethernet cards based on - the Solarflare Communications Solarstorm SFC4000 controller. + the Solarflare Communications Solarstorm SFC4000 and + SFC9000-family controllers. To compile this driver as a module, choose M here. The module will be called sfc. config SFC_MTD - bool "Solarflare Solarstorm SFC4000 flash MTD support" + bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support" depends on SFC && MTD && !(SFC=y && MTD=m) default y help - This exposes the on-board flash memory as an MTD device (e.g. - /dev/mtd1). This makes it possible to upload new boot code - to the NIC. + This exposes the on-board flash memory as MTD devices (e.g. + /dev/mtd1). This makes it possible to upload new firmware + to the NIC. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 223106b9344..1047b19c60a 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,6 +1,7 @@ -sfc-y += efx.o nic.o falcon.o tx.o rx.o falcon_gmac.o \ - falcon_xmac.o selftest.o ethtool.o qt202x_phy.o \ - mdio_10g.o tenxpress.o falcon_boards.o +sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ + falcon_gmac.o falcon_xmac.o mcdi_mac.o \ + selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ + tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index 6ad909bba95..bb5de4fe925 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h @@ -37,6 +37,8 @@ #define EFX_DWORD_2_WIDTH 32 #define EFX_DWORD_3_LBN 96 #define EFX_DWORD_3_WIDTH 32 +#define EFX_QWORD_0_LBN 0 +#define EFX_QWORD_0_WIDTH 64 /* Specified attribute (e.g. LBN) of the specified field */ #define EFX_VAL(field, attribute) field ## _ ## attribute diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 97a6ebdcaf2..4b5c786f0e2 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -25,6 +25,8 @@ #include "mdio_10g.h" #include "nic.h" +#include "mcdi.h" + /************************************************************************** * * Type name strings @@ -84,6 +86,7 @@ const char *efx_reset_type_names[] = { [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", [RESET_TYPE_TX_SKIP] = "TX_SKIP", + [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", }; #define EFX_MAX_MTU (9 * 1024) @@ -1191,6 +1194,15 @@ static void efx_start_all(struct efx_nic *efx) efx_nic_enable_interrupts(efx); + /* Switch to event based MCDI completions after enabling interrupts. + * If a reset has been scheduled, then we need to stay in polled mode. + * Rather than serialising efx_mcdi_mode_event() [which sleeps] and + * reset_pending [modified from an atomic context], we instead guarantee + * that efx_mcdi_mode_poll() isn't reverted erroneously */ + efx_mcdi_mode_event(efx); + if (efx->reset_pending != RESET_TYPE_NONE) + efx_mcdi_mode_poll(efx); + /* Start the hardware monitor if there is one. Otherwise (we're link * event driven), we have to poll the PHY because after an event queue * flush, we could have a missed a link state change */ @@ -1242,6 +1254,9 @@ static void efx_stop_all(struct efx_nic *efx) efx->type->stop_stats(efx); + /* Switch to MCDI polling on Siena before disabling interrupts */ + efx_mcdi_mode_poll(efx); + /* Disable interrupts and wait for ISR to complete */ efx_nic_disable_interrupts(efx); if (efx->legacy_irq) @@ -1445,6 +1460,8 @@ static int efx_net_open(struct net_device *net_dev) return -EIO; if (efx->phy_mode & PHY_MODE_SPECIAL) return -EBUSY; + if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) + return -EIO; /* Notify the kernel of the link state polled during driver load, * before the monitor starts running */ @@ -1895,6 +1912,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) case RESET_TYPE_TX_SKIP: method = RESET_TYPE_INVISIBLE; break; + case RESET_TYPE_MC_FAILURE: default: method = RESET_TYPE_ALL; break; @@ -1908,6 +1926,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) efx->reset_pending = method; + /* efx_process_channel() will no longer read events once a + * reset is scheduled. So switch back to poll'd MCDI completions. */ + efx_mcdi_mode_poll(efx); + queue_work(reset_workqueue, &efx->reset_work); } @@ -1923,6 +1945,10 @@ static struct pci_device_id efx_pci_table[] __devinitdata = { .driver_data = (unsigned long) &falcon_a1_nic_type}, {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), .driver_data = (unsigned long) &falcon_b0_nic_type}, + {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, + {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, {0} /* end of list */ }; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index fa40c7b66d7..b4470da2386 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -18,6 +18,8 @@ #define FALCON_A_P_DEVID 0x0703 #define FALCON_A_S_DEVID 0x6703 #define FALCON_B_P_DEVID 0x0710 +#define BETHPAGE_A_P_DEVID 0x0803 +#define SIENA_A_P_DEVID 0x0813 /* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ #define EFX_MEM_BAR 2 diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index 7a9e79ab931..b1f7a40ab15 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -144,6 +144,7 @@ enum efx_loopback_mode { * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors + * @RESET_TYPE_MC_FAILURE: MC reboot/assertion */ enum reset_type { RESET_TYPE_NONE = -1, @@ -158,6 +159,7 @@ enum reset_type { RESET_TYPE_RX_DESC_FETCH, RESET_TYPE_TX_DESC_FETCH, RESET_TYPE_TX_SKIP, + RESET_TYPE_MC_FAILURE, RESET_TYPE_MAX, }; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 012ee31db0c..5492b633660 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -236,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + siena_print_fwver(efx, info->fw_version, + sizeof(info->fw_version)); strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); } diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index d2af50f1747..c733863fa41 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -15,6 +15,9 @@ extern struct efx_mac_operations falcon_gmac_operations; extern struct efx_mac_operations falcon_xmac_operations; +extern struct efx_mac_operations efx_mcdi_mac_operations; extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); +extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, + u32 dma_len, int enable, int clear); #endif diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 65a22f193f9..ef561f8af4d 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -8,6 +8,7 @@ * by the Free Software Foundation, incorporated herein by reference. */ +#include #include #include #include @@ -18,12 +19,22 @@ #include "spi.h" #include "efx.h" #include "nic.h" +#include "mcdi.h" +#include "mcdi_pcol.h" #define EFX_SPI_VERIFY_BUF_LEN 16 +#define EFX_MCDI_CHUNK_LEN 128 struct efx_mtd_partition { struct mtd_info mtd; - size_t offset; + union { + struct { + bool updating; + u8 nvram_type; + u16 fw_subtype; + } mcdi; + size_t offset; + }; const char *type_name; char name[IFNAMSIZ + 20]; }; @@ -56,6 +67,7 @@ struct efx_mtd { container_of(mtd, struct efx_mtd_partition, mtd) static int falcon_mtd_probe(struct efx_nic *efx); +static int siena_mtd_probe(struct efx_nic *efx); /* SPI utilities */ @@ -223,9 +235,14 @@ static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) struct efx_mtd_partition *part; efx_for_each_partition(part, efx_mtd) - snprintf(part->name, sizeof(part->name), - "%s %s", efx_mtd->efx->name, - part->type_name); + if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0) + snprintf(part->name, sizeof(part->name), + "%s %s:%02x", efx_mtd->efx->name, + part->type_name, part->mcdi.fw_subtype); + else + snprintf(part->name, sizeof(part->name), + "%s %s", efx_mtd->efx->name, + part->type_name); } static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) @@ -285,7 +302,10 @@ void efx_mtd_rename(struct efx_nic *efx) int efx_mtd_probe(struct efx_nic *efx) { - return falcon_mtd_probe(efx); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + return siena_mtd_probe(efx); + else + return falcon_mtd_probe(efx); } /* Implementation of MTD operations for Falcon */ @@ -393,3 +413,240 @@ static int falcon_mtd_probe(struct efx_nic *efx) kfree(efx_mtd); return rc; } + +/* Implementation of MTD operations for Siena */ + +static int siena_mtd_read(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, u8 *buffer) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start; + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk; + int rc = 0; + + while (offset < end) { + chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); + rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, + buffer, chunk); + if (rc) + goto out; + offset += chunk; + buffer += chunk; + } +out: + *retlen = offset - start; + return rc; +} + +static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk = part->mtd.erasesize; + int rc = 0; + + if (!part->mcdi.updating) { + rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); + if (rc) + goto out; + part->mcdi.updating = 1; + } + + /* The MCDI interface can in fact do multiple erase blocks at once; + * but erasing may be slow, so we make multiple calls here to avoid + * tripping the MCDI RPC timeout. */ + while (offset < end) { + rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset, + chunk); + if (rc) + goto out; + offset += chunk; + } +out: + return rc; +} + +static int siena_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start; + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk; + int rc = 0; + + if (!part->mcdi.updating) { + rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); + if (rc) + goto out; + part->mcdi.updating = 1; + } + + while (offset < end) { + chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); + rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, + buffer, chunk); + if (rc) + goto out; + offset += chunk; + buffer += chunk; + } +out: + *retlen = offset - start; + return rc; +} + +static int siena_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + int rc = 0; + + if (part->mcdi.updating) { + part->mcdi.updating = 0; + rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type); + } + + return rc; +} + +static struct efx_mtd_ops siena_mtd_ops = { + .read = siena_mtd_read, + .erase = siena_mtd_erase, + .write = siena_mtd_write, + .sync = siena_mtd_sync, +}; + +struct siena_nvram_type_info { + int port; + const char *name; +}; + +static struct siena_nvram_type_info siena_nvram_types[] = { + [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, + [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, + [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, + [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, + [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, + [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, + [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, + [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, + [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, +}; + +static int siena_mtd_probe_partition(struct efx_nic *efx, + struct efx_mtd *efx_mtd, + unsigned int part_id, + unsigned int type) +{ + struct efx_mtd_partition *part = &efx_mtd->part[part_id]; + struct siena_nvram_type_info *info; + size_t size, erase_size; + bool protected; + int rc; + + if (type >= ARRAY_SIZE(siena_nvram_types)) + return -ENODEV; + + info = &siena_nvram_types[type]; + + if (info->port != efx_port_num(efx)) + return -ENODEV; + + rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); + if (rc) + return rc; + if (protected) + return -ENODEV; /* hide it */ + + part->mcdi.nvram_type = type; + part->type_name = info->name; + + part->mtd.type = MTD_NORFLASH; + part->mtd.flags = MTD_CAP_NORFLASH; + part->mtd.size = size; + part->mtd.erasesize = erase_size; + + return 0; +} + +static int siena_mtd_get_fw_subtypes(struct efx_nic *efx, + struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / + sizeof(uint16_t)]; + int rc; + + rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list); + if (rc) + return rc; + + efx_for_each_partition(part, efx_mtd) + part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type]; + + return 0; +} + +static int siena_mtd_probe(struct efx_nic *efx) +{ + struct efx_mtd *efx_mtd; + int rc = -ENODEV; + u32 nvram_types; + unsigned int type; + + ASSERT_RTNL(); + + rc = efx_mcdi_nvram_types(efx, &nvram_types); + if (rc) + return rc; + + efx_mtd = kzalloc(sizeof(*efx_mtd) + + hweight32(nvram_types) * sizeof(efx_mtd->part[0]), + GFP_KERNEL); + if (!efx_mtd) + return -ENOMEM; + + efx_mtd->name = "Siena NVRAM manager"; + + efx_mtd->ops = &siena_mtd_ops; + + type = 0; + efx_mtd->n_parts = 0; + + while (nvram_types != 0) { + if (nvram_types & 1) { + rc = siena_mtd_probe_partition(efx, efx_mtd, + efx_mtd->n_parts, type); + if (rc == 0) + efx_mtd->n_parts++; + else if (rc != -ENODEV) + goto fail; + } + type++; + nvram_types >>= 1; + } + + rc = siena_mtd_get_fw_subtypes(efx, efx_mtd); + if (rc) + goto fail; + + rc = efx_mtd_probe_device(efx, efx_mtd); +fail: + if (rc) + kfree(efx_mtd); + return rc; +} + diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 96d3f00df64..ec132038b26 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -706,6 +706,7 @@ union efx_multicast_hash { * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) * @mdio: PHY MDIO interface + * @mdio_bus: PHY MDIO bus ID (only used by Siena) * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @xmac_poll_required: XMAC link state needs polling * @link_advertising: Autonegotiation advertising flags @@ -756,6 +757,7 @@ struct efx_nic { struct efx_buffer irq_status; volatile signed int last_irq_cpu; + unsigned long irq_zero_count; struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; @@ -766,7 +768,7 @@ struct efx_nic { unsigned n_rx_nodesc_drop_cnt; - struct falcon_nic_data *nic_data; + void *nic_data; struct mutex mac_lock; struct work_struct mac_work; @@ -792,6 +794,7 @@ struct efx_nic { struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; + unsigned int mdio_bus; enum efx_phy_mode phy_mode; bool xmac_poll_required; @@ -824,6 +827,11 @@ static inline const char *efx_dev_name(struct efx_nic *efx) return efx_dev_registered(efx) ? efx->name : ""; } +static inline unsigned int efx_port_num(struct efx_nic *efx) +{ + return PCI_FUNC(efx->pci_dev->devfn); +} + /** * struct efx_nic_type - Efx device type definition * @probe: Probe the controller diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 55dbd7994b6..5ac4b1af839 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -997,6 +997,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) case FSE_AZ_EV_CODE_DRIVER_EV: efx_handle_driver_event(channel, &event); break; + case FSE_CZ_EV_CODE_MCDI_EV: + efx_mcdi_process_event(channel, &event); + break; default: EFX_ERR(channel->efx, "channel %d unknown event type %d" " (data " EFX_QWORD_FMT ")\n", channel->channel, @@ -1025,13 +1028,21 @@ int efx_nic_probe_eventq(struct efx_channel *channel) void efx_nic_init_eventq(struct efx_channel *channel) { - efx_oword_t evq_ptr; + efx_oword_t reg; struct efx_nic *efx = channel->efx; 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); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { + EFX_POPULATE_OWORD_3(reg, + FRF_CZ_TIMER_Q_EN, 1, + FRF_CZ_HOST_NOTIFY_MODE, 0, + FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); + efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); + } + /* Pin event queue buffer */ efx_init_special_buffer(efx, &channel->eventq); @@ -1039,11 +1050,11 @@ void efx_nic_init_eventq(struct efx_channel *channel) memset(channel->eventq.addr, 0xff, channel->eventq.len); /* Push event queue to card */ - EFX_POPULATE_OWORD_3(evq_ptr, + EFX_POPULATE_OWORD_3(reg, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); - efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, channel->channel); efx->type->push_irq_moderation(channel); @@ -1051,13 +1062,15 @@ void efx_nic_init_eventq(struct efx_channel *channel) void efx_nic_fini_eventq(struct efx_channel *channel) { - efx_oword_t eventq_ptr; + efx_oword_t reg; struct efx_nic *efx = channel->efx; /* Remove event queue from card */ - EFX_ZERO_OWORD(eventq_ptr); - efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, + EFX_ZERO_OWORD(reg); + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, channel->channel); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); /* Unpin event queue */ efx_fini_special_buffer(efx, &channel->eventq); @@ -1220,8 +1233,15 @@ static inline void efx_nic_interrupts(struct efx_nic *efx, bool enabled, bool force) { efx_oword_t int_en_reg_ker; + unsigned int level = 0; + + if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) + /* Set the level always even if we're generating a test + * interrupt, because our legacy interrupt handler is safe */ + level = 0x1f; - EFX_POPULATE_OWORD_2(int_en_reg_ker, + EFX_POPULATE_OWORD_3(int_en_reg_ker, + FRF_AZ_KER_INT_LEVE_SEL, level, FRF_AZ_KER_INT_KER, force, FRF_AZ_DRV_INT_EN_KER, enabled); efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); @@ -1334,15 +1354,30 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) if (unlikely(syserr)) return efx_nic_fatal_interrupt(efx); - /* Schedule processing of any interrupting queues */ - efx_for_each_channel(channel, efx) { - if ((queues & 1) || - efx_event_present( - efx_event(channel, channel->eventq_read_ptr))) { + if (queues != 0) { + if (EFX_WORKAROUND_15783(efx)) + efx->irq_zero_count = 0; + + /* Schedule processing of any interrupting queues */ + efx_for_each_channel(channel, efx) { + if (queues & 1) + efx_schedule_channel(channel); + queues >>= 1; + } + result = IRQ_HANDLED; + + } else if (EFX_WORKAROUND_15783(efx) && + efx->irq_zero_count++ == 0) { + efx_qword_t *event; + + /* Ensure we rearm all event queues */ + efx_for_each_channel(channel, efx) { + event = efx_event(channel, channel->eventq_read_ptr); + if (efx_event_present(event)) efx_schedule_channel(channel); - result = IRQ_HANDLED; } - queues >>= 1; + + result = IRQ_HANDLED; } if (result == IRQ_HANDLED) { diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index e7eb30488c1..57c510d8c34 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -14,6 +14,7 @@ #include #include "net_driver.h" #include "efx.h" +#include "mcdi.h" /* * Falcon hardware control @@ -23,6 +24,7 @@ enum { EFX_REV_FALCON_A0 = 0, EFX_REV_FALCON_A1 = 1, EFX_REV_FALCON_B0 = 2, + EFX_REV_SIENA_A0 = 3, }; static inline int efx_nic_rev(struct efx_nic *efx) @@ -32,6 +34,10 @@ static inline int efx_nic_rev(struct efx_nic *efx) extern u32 efx_nic_fpga_ver(struct efx_nic *efx); +static inline bool efx_nic_has_mc(struct efx_nic *efx) +{ + return efx_nic_rev(efx) >= EFX_REV_SIENA_A0; +} /* NIC has two interlinked PCI functions for the same port. */ static inline bool efx_nic_is_dual_func(struct efx_nic *efx) { @@ -123,8 +129,25 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) return &data->board; } +/** + * struct siena_nic_data - Siena NIC state + * @fw_version: Management controller firmware version + * @fw_build: Firmware build number + * @mcdi: Management-Controller-to-Driver Interface + * @wol_filter_id: Wake-on-LAN packet filter id + */ +struct siena_nic_data { + u64 fw_version; + u32 fw_build; + struct efx_mcdi_iface mcdi; + int wol_filter_id; +}; + +extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); + extern struct efx_nic_type falcon_a1_nic_type; extern struct efx_nic_type falcon_b0_nic_type; +extern struct efx_nic_type siena_a0_nic_type; /************************************************************************** * diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 2ad1cec2c72..64dff2d5952 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -41,4 +41,21 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops; extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); +/**************************************************************************** + * Siena managed PHYs + */ +extern struct efx_phy_operations efx_mcdi_phy_ops; + +extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, + u16 addr, u16 *value_out, u32 *status_out); +extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, + u16 addr, u16 value, u32 *status_out); +extern void efx_mcdi_phy_decode_link(struct efx_nic *efx, + struct efx_link_state *link_state, + u32 speed, u32 flags, u32 fcntl); +extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx); +extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa); + #endif diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 021d0d2d97f..ecee8f57d7f 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -18,6 +18,7 @@ #define EFX_WORKAROUND_ALWAYS(efx) 1 #define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) #define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) +#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ (efx)->phy_type == PHY_TYPE_SFT9001B) @@ -35,6 +36,10 @@ #define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB /* Truncated IPv4 packets can confuse the TX packet parser */ #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB +/* Legacy ISR read can return zero once */ +#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA +/* Legacy interrupt storm when interrupt fifo fills */ +#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA /* Spurious parity errors in TSORT buffers */ #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A -- cgit v1.2.3-70-g09d2 From 738a8f4b0c0e6ce7260e1514d41c764f334982e4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:16:05 +0000 Subject: sfc: Implement TSO for TCP/IPv6 Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 ++ drivers/net/sfc/ethtool.c | 20 +++++++++++++++++- drivers/net/sfc/tx.c | 52 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 14 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4b5c786f0e2..3c0d6bea126 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2208,6 +2208,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_GRO); + if (type->offload_features & NETIF_F_V6_CSUM) + net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 5492b633660..f6981216f1f 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -471,6 +471,23 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } +static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); + unsigned long features; + + features = NETIF_F_TSO; + if (efx->type->offload_features & NETIF_F_V6_CSUM) + features |= NETIF_F_TSO6; + + if (enable) + net_dev->features |= features; + else + net_dev->features &= ~features; + + return 0; +} + static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) { struct efx_nic *efx = netdev_priv(net_dev); @@ -834,7 +851,8 @@ const struct ethtool_ops efx_ethtool_ops = { .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, + /* Need to enable/disable TSO-IPv6 too */ + .set_tso = efx_ethtool_set_tso, .get_flags = ethtool_op_get_flags, .set_flags = ethtool_op_set_flags, .get_sset_count = efx_ethtool_get_sset_count, diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 389ede43e34..582fc752da9 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include "net_driver.h" @@ -531,6 +533,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) +#define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data) /** * struct tso_state - TSO state for an SKB @@ -543,6 +546,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) * @unmap_len: Length of SKB fragment * @unmap_addr: DMA address of SKB fragment * @unmap_single: DMA single vs page mapping flag + * @protocol: Network protocol (after any VLAN header) * @header_len: Number of bytes of header * @full_packet_size: Number of bytes to put in each outgoing segment * @@ -563,6 +567,7 @@ struct tso_state { dma_addr_t unmap_addr; bool unmap_single; + __be16 protocol; unsigned header_len; int full_packet_size; }; @@ -570,9 +575,9 @@ struct tso_state { /* * Verify that our various assumptions about sk_buffs and the conditions - * under which TSO will be attempted hold true. + * under which TSO will be attempted hold true. Return the protocol number. */ -static void efx_tso_check_safe(struct sk_buff *skb) +static __be16 efx_tso_check_protocol(struct sk_buff *skb) { __be16 protocol = skb->protocol; @@ -587,13 +592,22 @@ static void efx_tso_check_safe(struct sk_buff *skb) if (protocol == htons(ETH_P_IP)) skb_set_transport_header(skb, sizeof(*veh) + 4 * ip_hdr(skb)->ihl); + else if (protocol == htons(ETH_P_IPV6)) + skb_set_transport_header(skb, sizeof(*veh) + + sizeof(struct ipv6hdr)); } - EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); - EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); + if (protocol == htons(ETH_P_IP)) { + EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); + } else { + EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6)); + EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); + } EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) + (tcp_hdr(skb)->doff << 2u)) > skb_headlen(skb)); + + return protocol; } @@ -836,7 +850,10 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb) + PTR_DIFF(tcp_hdr(skb), skb->data)); st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; - st->ipv4_id = ntohs(ip_hdr(skb)->id); + if (st->protocol == htons(ETH_P_IP)) + st->ipv4_id = ntohs(ip_hdr(skb)->id); + else + st->ipv4_id = 0; st->seqnum = ntohl(tcp_hdr(skb)->seq); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); @@ -951,7 +968,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, struct tso_state *st) { struct efx_tso_header *tsoh; - struct iphdr *tsoh_iph; struct tcphdr *tsoh_th; unsigned ip_length; u8 *header; @@ -975,7 +991,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, header = TSOH_BUFFER(tsoh); tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); - tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); /* Copy and update the headers. */ memcpy(header, skb->data, st->header_len); @@ -993,11 +1008,22 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, tsoh_th->fin = tcp_hdr(skb)->fin; tsoh_th->psh = tcp_hdr(skb)->psh; } - tsoh_iph->tot_len = htons(ip_length); - /* Linux leaves suitable gaps in the IP ID space for us to fill. */ - tsoh_iph->id = htons(st->ipv4_id); - st->ipv4_id++; + if (st->protocol == htons(ETH_P_IP)) { + struct iphdr *tsoh_iph = + (struct iphdr *)(header + SKB_IPV4_OFF(skb)); + + tsoh_iph->tot_len = htons(ip_length); + + /* Linux leaves suitable gaps in the IP ID space for us to fill. */ + tsoh_iph->id = htons(st->ipv4_id); + st->ipv4_id++; + } else { + struct ipv6hdr *tsoh_iph = + (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb)); + + tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph)); + } st->packet_space = skb_shinfo(skb)->gso_size; ++tx_queue->tso_packets; @@ -1027,8 +1053,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, int frag_i, rc, rc2 = NETDEV_TX_OK; struct tso_state state; - /* Verify TSO is safe - these checks should never fail. */ - efx_tso_check_safe(skb); + /* Find the packet protocol and sanity-check it */ + state.protocol = efx_tso_check_protocol(skb); EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); -- cgit v1.2.3-70-g09d2 From 906bb26c0624d87df74e6642f2d74cde176fcc12 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Nov 2009 15:16:19 +0000 Subject: sfc: Update version, copyright dates, authors This driver has been mostly rewritten since Michael Brown's initial work, so swap the order of the authors. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/bitfield.h | 2 +- drivers/net/sfc/efx.c | 6 +++--- drivers/net/sfc/efx.h | 2 +- drivers/net/sfc/enum.h | 2 +- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/falcon_boards.c | 2 +- drivers/net/sfc/falcon_gmac.c | 2 +- drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/mac.h | 2 +- drivers/net/sfc/mdio_10g.c | 2 +- drivers/net/sfc/mdio_10g.h | 2 +- drivers/net/sfc/mtd.c | 2 +- drivers/net/sfc/net_driver.h | 4 ++-- drivers/net/sfc/nic.c | 2 +- drivers/net/sfc/nic.h | 2 +- drivers/net/sfc/phy.h | 2 +- drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/rx.c | 2 +- drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/tenxpress.c | 2 +- drivers/net/sfc/tx.c | 2 +- drivers/net/sfc/workarounds.h | 2 +- 23 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers/net/sfc/efx.c') diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index bb5de4fe925..098ac2ad757 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 3c0d6bea126..f983e3b507c 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -2453,8 +2453,8 @@ static void __exit efx_exit_module(void) module_init(efx_init_module); module_exit(efx_exit_module); -MODULE_AUTHOR("Michael Brown and " - "Solarflare Communications"); +MODULE_AUTHOR("Solarflare Communications and " + "Michael Brown "); MODULE_DESCRIPTION("Solarflare Communications network driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, efx_pci_table); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index b4470da2386..a615ac05153 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index b1f7a40ab15..384cfe3b1be 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index f6981216f1f..6c0bbed8c47 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 48d28d828d4..17afcd26e87 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index fa4d4c72ccd..bf0b96af533 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index aa9b689cadc..7dadfcbd6ce 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index cd63f242698..3da933f8f07 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index c733863fa41..f1aa5f37489 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 19496da3e2b..1574e52f059 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index dbc8e7de292..f6ac9503339 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index ef561f8af4d..3a464529a46 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ec132038b26..34c381f009b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -38,7 +38,7 @@ #ifndef EFX_DRIVER_NAME #define EFX_DRIVER_NAME "sfc" #endif -#define EFX_DRIVER_VERSION "2.3" +#define EFX_DRIVER_VERSION "3.0" #ifdef EFX_ENABLE_DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 5ac4b1af839..a577be22786 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 57c510d8c34..9351c0331a4 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 64dff2d5952..5bc26137257 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 957e534a179..3800fc791b2 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 03eace323d3..a97c923b560 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 1635f575112..14949bb303a 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index ff97133c2b9..ca11572a49a 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 582fc752da9..e669f94e821 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index ecee8f57d7f..acd9c734e48 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published -- cgit v1.2.3-70-g09d2