Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sfc: Rework MAC, PHY and board event handling

From: Steve Hodgson <shodgson@solarflare.com>

MAC, PHY and board events may be separately enabled and signalled.
Our current arrangement of chaining the polling functions can result
in events being missed. Change them to be more independent.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ben Hutchings and committed by
David S. Miller
766ca0fa 04cc8cac

+111 -114
+42 -21
drivers/net/sfc/efx.c
··· 612 612 /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() 613 613 * we don't efx_reconfigure_port() if the port is disabled. Care is taken 614 614 * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ 615 - static void efx_reconfigure_work(struct work_struct *data) 615 + static void efx_phy_work(struct work_struct *data) 616 616 { 617 - struct efx_nic *efx = container_of(data, struct efx_nic, 618 - reconfigure_work); 617 + struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); 619 618 620 619 mutex_lock(&efx->mac_lock); 621 620 if (efx->port_enabled) 622 621 __efx_reconfigure_port(efx); 622 + mutex_unlock(&efx->mac_lock); 623 + } 624 + 625 + static void efx_mac_work(struct work_struct *data) 626 + { 627 + struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); 628 + 629 + mutex_lock(&efx->mac_lock); 630 + if (efx->port_enabled) 631 + efx->mac_op->irq(efx); 623 632 mutex_unlock(&efx->mac_lock); 624 633 } 625 634 ··· 697 688 698 689 /* Allow efx_reconfigure_port() to be scheduled, and close the window 699 690 * between efx_stop_port and efx_flush_all whereby a previously scheduled 700 - * efx_reconfigure_port() may have been cancelled */ 691 + * efx_phy_work()/efx_mac_work() may have been cancelled */ 701 692 static void efx_start_port(struct efx_nic *efx) 702 693 { 703 694 EFX_LOG(efx, "start port\n"); ··· 706 697 mutex_lock(&efx->mac_lock); 707 698 efx->port_enabled = true; 708 699 __efx_reconfigure_port(efx); 700 + efx->mac_op->irq(efx); 709 701 mutex_unlock(&efx->mac_lock); 710 702 } 711 703 712 - /* Prevent efx_reconfigure_work and efx_monitor() from executing, and 713 - * efx_set_multicast_list() from scheduling efx_reconfigure_work. 714 - * efx_reconfigure_work can still be scheduled via NAPI processing 715 - * until efx_flush_all() is called */ 704 + /* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, 705 + * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work 706 + * and efx_mac_work may still be scheduled via NAPI processing until 707 + * efx_flush_all() is called */ 716 708 static void efx_stop_port(struct efx_nic *efx) 717 709 { 718 710 EFX_LOG(efx, "stop port\n"); ··· 1104 1094 cancel_delayed_work_sync(&rx_queue->work); 1105 1095 1106 1096 /* Stop scheduled port reconfigurations */ 1107 - cancel_work_sync(&efx->reconfigure_work); 1097 + cancel_work_sync(&efx->mac_work); 1098 + cancel_work_sync(&efx->phy_work); 1108 1099 1109 1100 } 1110 1101 ··· 1142 1131 * window to loose phy events */ 1143 1132 efx_stop_port(efx); 1144 1133 1145 - /* Flush reconfigure_work, refill_workqueue, monitor_work */ 1134 + /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ 1146 1135 efx_flush_all(efx); 1147 1136 1148 1137 /* Isolate the MAC from the TX and RX engines, so that queue ··· 1214 1203 { 1215 1204 struct efx_nic *efx = container_of(data, struct efx_nic, 1216 1205 monitor_work.work); 1206 + int rc; 1217 1207 1218 1208 EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", 1219 1209 raw_smp_processor_id()); 1220 1210 1221 - 1222 1211 /* If the mac_lock is already held then it is likely a port 1223 1212 * reconfiguration is already in place, which will likely do 1224 1213 * most of the work of check_hw() anyway. */ 1225 - if (!mutex_trylock(&efx->mac_lock)) { 1226 - queue_delayed_work(efx->workqueue, &efx->monitor_work, 1227 - efx_monitor_interval); 1228 - return; 1214 + if (!mutex_trylock(&efx->mac_lock)) 1215 + goto out_requeue; 1216 + if (!efx->port_enabled) 1217 + goto out_unlock; 1218 + rc = efx->board_info.monitor(efx); 1219 + if (rc) { 1220 + EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", 1221 + (rc == -ERANGE) ? "reported fault" : "failed"); 1222 + efx->phy_mode |= PHY_MODE_LOW_POWER; 1223 + falcon_sim_phy_event(efx); 1229 1224 } 1225 + efx->phy_op->poll(efx); 1226 + efx->mac_op->poll(efx); 1230 1227 1231 - if (efx->port_enabled) 1232 - efx->mac_op->check_hw(efx); 1228 + out_unlock: 1233 1229 mutex_unlock(&efx->mac_lock); 1234 - 1230 + out_requeue: 1235 1231 queue_delayed_work(efx->workqueue, &efx->monitor_work, 1236 1232 efx_monitor_interval); 1237 1233 } ··· 1495 1477 return; 1496 1478 1497 1479 if (changed) 1498 - queue_work(efx->workqueue, &efx->reconfigure_work); 1480 + queue_work(efx->workqueue, &efx->phy_work); 1499 1481 1500 1482 /* Create and activate new global multicast hash table */ 1501 1483 falcon_set_multicast_hash(efx); ··· 1818 1800 1819 1801 static struct efx_mac_operations efx_dummy_mac_operations = { 1820 1802 .reconfigure = efx_port_dummy_op_void, 1803 + .poll = efx_port_dummy_op_void, 1804 + .irq = efx_port_dummy_op_void, 1821 1805 }; 1822 1806 1823 1807 static struct efx_phy_operations efx_dummy_phy_operations = { 1824 1808 .init = efx_port_dummy_op_int, 1825 1809 .reconfigure = efx_port_dummy_op_void, 1826 - .check_hw = efx_port_dummy_op_int, 1810 + .poll = efx_port_dummy_op_void, 1827 1811 .fini = efx_port_dummy_op_void, 1828 1812 .clear_interrupt = efx_port_dummy_op_void, 1829 1813 }; ··· 1877 1857 efx->mac_op = &efx_dummy_mac_operations; 1878 1858 efx->phy_op = &efx_dummy_phy_operations; 1879 1859 efx->mii.dev = net_dev; 1880 - INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); 1860 + INIT_WORK(&efx->phy_work, efx_phy_work); 1861 + INIT_WORK(&efx->mac_work, efx_mac_work); 1881 1862 atomic_set(&efx->netif_stop_count, 1); 1882 1863 1883 1864 for (i = 0; i < EFX_MAX_CHANNELS; i++) {
+9 -11
drivers/net/sfc/falcon.c
··· 910 910 efx_qword_t *event) 911 911 { 912 912 struct efx_nic *efx = channel->efx; 913 - bool is_phy_event = false, handled = false; 913 + bool handled = false; 914 914 915 - /* Check for interrupt on either port. Some boards have a 916 - * single PHY wired to the interrupt line for port 1. */ 917 915 if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || 918 916 EFX_QWORD_FIELD(*event, G_PHY1_INTR) || 919 - EFX_QWORD_FIELD(*event, XG_PHY_INTR)) 920 - is_phy_event = true; 917 + EFX_QWORD_FIELD(*event, XG_PHY_INTR) || 918 + EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) { 919 + efx->phy_op->clear_interrupt(efx); 920 + queue_work(efx->workqueue, &efx->phy_work); 921 + handled = true; 922 + } 921 923 922 924 if ((falcon_rev(efx) >= FALCON_REV_B0) && 923 - EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) 924 - is_phy_event = true; 925 - 926 - if (is_phy_event) { 927 - efx->phy_op->clear_interrupt(efx); 928 - queue_work(efx->workqueue, &efx->reconfigure_work); 925 + EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) { 926 + queue_work(efx->workqueue, &efx->mac_work); 929 927 handled = true; 930 928 } 931 929
+2 -6
drivers/net/sfc/falcon_gmac.c
··· 221 221 mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; 222 222 } 223 223 224 - static int falcon_check_gmac(struct efx_nic *efx) 225 - { 226 - return efx->phy_op->check_hw(efx); 227 - } 228 - 229 224 struct efx_mac_operations falcon_gmac_operations = { 230 225 .reconfigure = falcon_reconfigure_gmac, 231 226 .update_stats = falcon_update_stats_gmac, 232 - .check_hw = falcon_check_gmac, 227 + .irq = efx_port_dummy_op_void, 228 + .poll = efx_port_dummy_op_void, 233 229 };
+2
drivers/net/sfc/falcon_hwdefs.h
··· 1051 1051 #define XG_MNT_INTR_B0_WIDTH 1 1052 1052 #define RX_RECOVERY_A1_LBN 11 1053 1053 #define RX_RECOVERY_A1_WIDTH 1 1054 + #define XFP_PHY_INTR_LBN 10 1055 + #define XFP_PHY_INTR_WIDTH 1 1054 1056 #define XG_PHY_INTR_LBN 9 1055 1057 #define XG_PHY_INTR_WIDTH 1 1056 1058 #define G_PHY1_INTR_LBN 8
+22 -20
drivers/net/sfc/falcon_xmac.c
··· 342 342 mac_stats->rx_control * 64); 343 343 } 344 344 345 - static int falcon_check_xmac(struct efx_nic *efx) 345 + static void falcon_xmac_irq(struct efx_nic *efx) 346 346 { 347 - bool xaui_link_ok; 348 - int rc; 347 + /* The XGMII link has a transient fault, which indicates either: 348 + * - there's a transient xgmii fault 349 + * - falcon's end of the xaui link may need a kick 350 + * - the wire-side link may have gone down, but the lasi/poll() 351 + * hasn't noticed yet. 352 + * 353 + * We only want to even bother polling XAUI if we're confident it's 354 + * not (1) or (3). In both cases, the only reliable way to spot this 355 + * is to wait a bit. We do this here by forcing the mac link state 356 + * to down, and waiting for the mac poll to come round and check 357 + */ 358 + efx->mac_up = false; 359 + } 349 360 350 - if ((efx->loopback_mode == LOOPBACK_NETWORK) || 351 - efx_phy_mode_disabled(efx->phy_mode)) 352 - return 0; 361 + static void falcon_poll_xmac(struct efx_nic *efx) 362 + { 363 + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) 364 + return; 353 365 354 366 falcon_mask_status_intr(efx, false); 355 - xaui_link_ok = falcon_xaui_link_ok(efx); 356 - 357 - if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) 358 - falcon_reset_xaui(efx); 359 - 360 - /* Call the PHY check_hw routine */ 361 - rc = efx->phy_op->check_hw(efx); 362 - 363 - /* Unmask interrupt if everything was (and still is) ok */ 364 - if (xaui_link_ok && efx->link_up) 365 - falcon_mask_status_intr(efx, true); 366 - 367 - return rc; 367 + falcon_check_xaui_link_up(efx, 1); 368 + falcon_mask_status_intr(efx, true); 368 369 } 369 370 370 371 struct efx_mac_operations falcon_xmac_operations = { 371 372 .reconfigure = falcon_reconfigure_xmac, 372 373 .update_stats = falcon_update_stats_xmac, 373 - .check_hw = falcon_check_xmac, 374 + .irq = falcon_xmac_irq, 375 + .poll = falcon_poll_xmac, 374 376 };
+14 -10
drivers/net/sfc/net_driver.h
··· 544 544 * struct efx_mac_operations - Efx MAC operations table 545 545 * @reconfigure: Reconfigure MAC. Serialised by the mac_lock 546 546 * @update_stats: Update statistics 547 - * @check_hw: Check hardware. Serialised by the mac_lock 547 + * @irq: Hardware MAC event callback. Serialised by the mac_lock 548 + * @poll: Poll for hardware state. Serialised by the mac_lock 548 549 */ 549 550 struct efx_mac_operations { 550 551 void (*reconfigure) (struct efx_nic *efx); 551 552 void (*update_stats) (struct efx_nic *efx); 552 - int (*check_hw) (struct efx_nic *efx); 553 + void (*irq) (struct efx_nic *efx); 554 + void (*poll) (struct efx_nic *efx); 553 555 }; 554 556 555 557 /** ··· 561 559 * @reconfigure: Reconfigure PHY (e.g. for new link parameters) 562 560 * @clear_interrupt: Clear down interrupt 563 561 * @blink: Blink LEDs 564 - * @check_hw: Check hardware 562 + * @poll: Poll for hardware state. Serialised by the mac_lock. 565 563 * @get_settings: Get ethtool settings. Serialised by the mac_lock. 566 564 * @set_settings: Set ethtool settings. Serialised by the mac_lock. 567 565 * @set_xnp_advertise: Set abilities advertised in Extended Next Page ··· 575 573 void (*fini) (struct efx_nic *efx); 576 574 void (*reconfigure) (struct efx_nic *efx); 577 575 void (*clear_interrupt) (struct efx_nic *efx); 578 - int (*check_hw) (struct efx_nic *efx); 576 + void (*poll) (struct efx_nic *efx); 579 577 int (*test) (struct efx_nic *efx); 580 578 void (*get_settings) (struct efx_nic *efx, 581 579 struct ethtool_cmd *ecmd); ··· 730 728 * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, 731 729 * @port_inhibited, efx_monitor() and efx_reconfigure_port() 732 730 * @port_enabled: Port enabled indicator. 733 - * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and 734 - * efx_reconfigure_work with kernel interfaces. Safe to read under any 735 - * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must 736 - * be held to modify it. 731 + * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), 732 + * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read 733 + * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all 734 + * three must be held to modify it. 737 735 * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock 738 736 * @port_initialized: Port initialized? 739 737 * @net_dev: Operating system network device. Consider holding the rtnl lock ··· 764 762 * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. 765 763 * @multicast_hash: Multicast hash table 766 764 * @wanted_fc: Wanted flow control flags 767 - * @reconfigure_work: work item for dealing with PHY events 765 + * @phy_work: work item for dealing with PHY events 766 + * @mac_work: work item for dealing with MAC events 768 767 * @loopback_mode: Loopback status 769 768 * @loopback_modes: Supported loopback mode bitmask 770 769 * @loopback_selftest: Offline self-test private state ··· 813 810 struct falcon_nic_data *nic_data; 814 811 815 812 struct mutex mac_lock; 813 + struct work_struct mac_work; 816 814 bool port_enabled; 817 815 bool port_inhibited; 818 816 ··· 834 830 835 831 enum phy_type phy_type; 836 832 spinlock_t phy_lock; 833 + struct work_struct phy_work; 837 834 struct efx_phy_operations *phy_op; 838 835 void *phy_data; 839 836 struct mii_if_info mii; ··· 850 845 bool promiscuous; 851 846 union efx_multicast_hash multicast_hash; 852 847 enum efx_fc_type wanted_fc; 853 - struct work_struct reconfigure_work; 854 848 855 849 atomic_t rx_reset; 856 850 enum efx_loopback_mode loopback_mode;
+4 -2
drivers/net/sfc/selftest.c
··· 594 594 efx->loopback_mode = mode; 595 595 efx_reconfigure_port(efx); 596 596 597 - /* Wait for the PHY to signal the link is up */ 597 + /* Wait for the PHY to signal the link is up. Interrupts 598 + * are enabled for PHY's using LASI, otherwise we poll() 599 + * quickly */ 598 600 count = 0; 599 601 do { 600 602 struct efx_channel *channel = &efx->channel[0]; 601 603 602 - efx->mac_op->check_hw(efx); 604 + efx->phy_op->poll(efx); 603 605 schedule_timeout_uninterruptible(HZ / 10); 604 606 if (channel->work_pending) 605 607 efx_process_channel_now(channel);
+14 -30
drivers/net/sfc/tenxpress.c
··· 348 348 efx->link_fc = mdio_clause45_get_pause(efx); 349 349 } 350 350 351 - static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) 352 - { 353 - /* Nothing done here - LASI interrupts aren't reliable so poll */ 354 - } 355 - 356 - 357 351 /* Poll PHY for interrupt */ 358 - static int tenxpress_phy_check_hw(struct efx_nic *efx) 352 + static void tenxpress_phy_poll(struct efx_nic *efx) 359 353 { 360 354 struct tenxpress_phy_data *phy_data = efx->phy_data; 361 - bool link_ok; 362 - int rc = 0; 355 + bool change = false, link_ok; 356 + unsigned link_fc; 363 357 364 358 link_ok = tenxpress_link_ok(efx); 359 + if (link_ok != efx->link_up) { 360 + change = true; 361 + } else { 362 + link_fc = mdio_clause45_get_pause(efx); 363 + if (link_fc != efx->link_fc) 364 + change = true; 365 + } 365 366 tenxpress_check_bad_lp(efx, link_ok); 366 367 367 - if (link_ok != efx->link_up) 368 + if (change) 368 369 falcon_sim_phy_event(efx); 369 370 370 371 if (phy_data->phy_mode != PHY_MODE_NORMAL) 371 - return 0; 372 + return; 372 373 373 374 if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { 374 375 EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); 375 376 falcon_reset_xaui(efx); 376 377 atomic_set(&phy_data->bad_crc_count, 0); 377 378 } 378 - 379 - rc = efx->board_info.monitor(efx); 380 - if (rc) { 381 - EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", 382 - (rc == -ERANGE) ? "reported fault" : "failed"); 383 - if (efx->phy_mode & PHY_MODE_OFF) { 384 - /* Assume that board has shut PHY off */ 385 - phy_data->phy_mode = PHY_MODE_OFF; 386 - } else { 387 - efx->phy_mode |= PHY_MODE_LOW_POWER; 388 - mdio_clause45_set_mmds_lpower(efx, true, 389 - efx->phy_op->mmds); 390 - phy_data->phy_mode |= PHY_MODE_LOW_POWER; 391 - } 392 - } 393 - 394 - return rc; 395 379 } 396 380 397 381 static void tenxpress_phy_fini(struct efx_nic *efx) ··· 445 461 .macs = EFX_XMAC, 446 462 .init = tenxpress_phy_init, 447 463 .reconfigure = tenxpress_phy_reconfigure, 448 - .check_hw = tenxpress_phy_check_hw, 464 + .poll = tenxpress_phy_poll, 449 465 .fini = tenxpress_phy_fini, 450 - .clear_interrupt = tenxpress_phy_clear_interrupt, 466 + .clear_interrupt = efx_port_dummy_op_void, 451 467 .test = tenxpress_phy_test, 452 468 .get_settings = tenxpress_get_settings, 453 469 .set_settings = mdio_clause45_set_settings,
+2 -14
drivers/net/sfc/xfp_phy.c
··· 119 119 return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); 120 120 } 121 121 122 - static int xfp_phy_check_hw(struct efx_nic *efx) 122 + static void xfp_phy_poll(struct efx_nic *efx) 123 123 { 124 - int rc = 0; 125 124 int link_up = xfp_link_ok(efx); 126 125 /* Simulate a PHY event if link state has changed */ 127 126 if (link_up != efx->link_up) 128 127 falcon_sim_phy_event(efx); 129 - 130 - rc = efx->board_info.monitor(efx); 131 - if (rc) { 132 - struct xfp_phy_data *phy_data = efx->phy_data; 133 - EFX_ERR(efx, "XFP sensor alert; putting PHY into low power\n"); 134 - efx->phy_mode |= PHY_MODE_LOW_POWER; 135 - mdio_clause45_set_mmds_lpower(efx, 1, XFP_REQUIRED_DEVS); 136 - phy_data->phy_mode |= PHY_MODE_LOW_POWER; 137 - } 138 - 139 - return rc; 140 128 } 141 129 142 130 static void xfp_phy_reconfigure(struct efx_nic *efx) ··· 161 173 .macs = EFX_XMAC, 162 174 .init = xfp_phy_init, 163 175 .reconfigure = xfp_phy_reconfigure, 164 - .check_hw = xfp_phy_check_hw, 176 + .poll = xfp_phy_poll, 165 177 .fini = xfp_phy_fini, 166 178 .clear_interrupt = xfp_phy_clear_interrupt, 167 179 .get_settings = mdio_clause45_get_settings,