Commit f8d59f7826aa73c5e7682fbed6db38020635d466

Authored by Bruce Allan
Committed by Jeff Garzik
1 parent d53f706da8

e1000e: test for unusable MSI support

Some systems do not like 82571/2 use of 16-bit MSI messages and some
other systems claim to support MSI, but neither really works.  Setup a
test MSI handler to detect whether or not MSI is working properly, and
if not, fallback to legacy INTx interrupts.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

Showing 3 changed files with 164 additions and 11 deletions Side-by-side Diff

drivers/net/e1000e/defines.h
... ... @@ -389,7 +389,7 @@
389 389  
390 390 /* Interrupt Cause Set */
391 391 #define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
392   -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
  392 +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */
393 393 #define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */
394 394  
395 395 /* Transmit Descriptor Control */
drivers/net/e1000e/e1000.h
... ... @@ -326,6 +326,7 @@
326 326 #define FLAG_RX_CSUM_ENABLED (1 << 28)
327 327 #define FLAG_TSO_FORCE (1 << 29)
328 328 #define FLAG_RX_RESTART_NOW (1 << 30)
  329 +#define FLAG_MSI_TEST_FAILED (1 << 31)
329 330  
330 331 #define E1000_RX_DESC_PS(R, i) \
331 332 (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
drivers/net/e1000e/netdev.c
... ... @@ -1236,26 +1236,36 @@
1236 1236 return IRQ_HANDLED;
1237 1237 }
1238 1238  
  1239 +/**
  1240 + * e1000_request_irq - initialize interrupts
  1241 + *
  1242 + * Attempts to configure interrupts using the best available
  1243 + * capabilities of the hardware and kernel.
  1244 + **/
1239 1245 static int e1000_request_irq(struct e1000_adapter *adapter)
1240 1246 {
1241 1247 struct net_device *netdev = adapter->netdev;
1242   - irq_handler_t handler = e1000_intr;
1243 1248 int irq_flags = IRQF_SHARED;
1244 1249 int err;
1245 1250  
1246   - if (!pci_enable_msi(adapter->pdev)) {
1247   - adapter->flags |= FLAG_MSI_ENABLED;
1248   - handler = e1000_intr_msi;
1249   - irq_flags = 0;
  1251 + if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
  1252 + err = pci_enable_msi(adapter->pdev);
  1253 + if (!err) {
  1254 + adapter->flags |= FLAG_MSI_ENABLED;
  1255 + irq_flags = 0;
  1256 + }
1250 1257 }
1251 1258  
1252   - err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
1253   - netdev);
  1259 + err = request_irq(adapter->pdev->irq,
  1260 + ((adapter->flags & FLAG_MSI_ENABLED) ?
  1261 + &e1000_intr_msi : &e1000_intr),
  1262 + irq_flags, netdev->name, netdev);
1254 1263 if (err) {
1255   - e_err("Unable to allocate %s interrupt (return: %d)\n",
1256   - adapter->flags & FLAG_MSI_ENABLED ? "MSI":"INTx", err);
1257   - if (adapter->flags & FLAG_MSI_ENABLED)
  1264 + if (adapter->flags & FLAG_MSI_ENABLED) {
1258 1265 pci_disable_msi(adapter->pdev);
  1266 + adapter->flags &= ~FLAG_MSI_ENABLED;
  1267 + }
  1268 + e_err("Unable to allocate interrupt, Error: %d\n", err);
1259 1269 }
1260 1270  
1261 1271 return err;
... ... @@ -2595,6 +2605,135 @@
2595 2605 }
2596 2606  
2597 2607 /**
  2608 + * e1000_intr_msi_test - Interrupt Handler
  2609 + * @irq: interrupt number
  2610 + * @data: pointer to a network interface device structure
  2611 + **/
  2612 +static irqreturn_t e1000_intr_msi_test(int irq, void *data)
  2613 +{
  2614 + struct net_device *netdev = data;
  2615 + struct e1000_adapter *adapter = netdev_priv(netdev);
  2616 + struct e1000_hw *hw = &adapter->hw;
  2617 + u32 icr = er32(ICR);
  2618 +
  2619 + e_dbg("%s: icr is %08X\n", netdev->name, icr);
  2620 + if (icr & E1000_ICR_RXSEQ) {
  2621 + adapter->flags &= ~FLAG_MSI_TEST_FAILED;
  2622 + wmb();
  2623 + }
  2624 +
  2625 + return IRQ_HANDLED;
  2626 +}
  2627 +
  2628 +/**
  2629 + * e1000_test_msi_interrupt - Returns 0 for successful test
  2630 + * @adapter: board private struct
  2631 + *
  2632 + * code flow taken from tg3.c
  2633 + **/
  2634 +static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
  2635 +{
  2636 + struct net_device *netdev = adapter->netdev;
  2637 + struct e1000_hw *hw = &adapter->hw;
  2638 + int err;
  2639 +
  2640 + /* poll_enable hasn't been called yet, so don't need disable */
  2641 + /* clear any pending events */
  2642 + er32(ICR);
  2643 +
  2644 + /* free the real vector and request a test handler */
  2645 + e1000_free_irq(adapter);
  2646 +
  2647 + /* Assume that the test fails, if it succeeds then the test
  2648 + * MSI irq handler will unset this flag */
  2649 + adapter->flags |= FLAG_MSI_TEST_FAILED;
  2650 +
  2651 + err = pci_enable_msi(adapter->pdev);
  2652 + if (err)
  2653 + goto msi_test_failed;
  2654 +
  2655 + err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0,
  2656 + netdev->name, netdev);
  2657 + if (err) {
  2658 + pci_disable_msi(adapter->pdev);
  2659 + goto msi_test_failed;
  2660 + }
  2661 +
  2662 + wmb();
  2663 +
  2664 + e1000_irq_enable(adapter);
  2665 +
  2666 + /* fire an unusual interrupt on the test handler */
  2667 + ew32(ICS, E1000_ICS_RXSEQ);
  2668 + e1e_flush();
  2669 + msleep(50);
  2670 +
  2671 + e1000_irq_disable(adapter);
  2672 +
  2673 + rmb();
  2674 +
  2675 + if (adapter->flags & FLAG_MSI_TEST_FAILED) {
  2676 + err = -EIO;
  2677 + e_info("MSI interrupt test failed!\n");
  2678 + }
  2679 +
  2680 + free_irq(adapter->pdev->irq, netdev);
  2681 + pci_disable_msi(adapter->pdev);
  2682 +
  2683 + if (err == -EIO)
  2684 + goto msi_test_failed;
  2685 +
  2686 + /* okay so the test worked, restore settings */
  2687 + e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name);
  2688 +msi_test_failed:
  2689 + /* restore the original vector, even if it failed */
  2690 + e1000_request_irq(adapter);
  2691 + return err;
  2692 +}
  2693 +
  2694 +/**
  2695 + * e1000_test_msi - Returns 0 if MSI test succeeds or INTx mode is restored
  2696 + * @adapter: board private struct
  2697 + *
  2698 + * code flow taken from tg3.c, called with e1000 interrupts disabled.
  2699 + **/
  2700 +static int e1000_test_msi(struct e1000_adapter *adapter)
  2701 +{
  2702 + int err;
  2703 + u16 pci_cmd;
  2704 +
  2705 + if (!(adapter->flags & FLAG_MSI_ENABLED))
  2706 + return 0;
  2707 +
  2708 + /* disable SERR in case the MSI write causes a master abort */
  2709 + pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
  2710 + pci_write_config_word(adapter->pdev, PCI_COMMAND,
  2711 + pci_cmd & ~PCI_COMMAND_SERR);
  2712 +
  2713 + err = e1000_test_msi_interrupt(adapter);
  2714 +
  2715 + /* restore previous setting of command word */
  2716 + pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
  2717 +
  2718 + /* success ! */
  2719 + if (!err)
  2720 + return 0;
  2721 +
  2722 + /* EIO means MSI test failed */
  2723 + if (err != -EIO)
  2724 + return err;
  2725 +
  2726 + /* back to INTx mode */
  2727 + e_warn("MSI interrupt test failed, using legacy interrupt.\n");
  2728 +
  2729 + e1000_free_irq(adapter);
  2730 +
  2731 + err = e1000_request_irq(adapter);
  2732 +
  2733 + return err;
  2734 +}
  2735 +
  2736 +/**
2598 2737 * e1000_open - Called when a network interface is made active
2599 2738 * @netdev: network interface device structure
2600 2739 *
... ... @@ -2651,6 +2790,19 @@
2651 2790 err = e1000_request_irq(adapter);
2652 2791 if (err)
2653 2792 goto err_req_irq;
  2793 +
  2794 + /*
  2795 + * Work around PCIe errata with MSI interrupts causing some chipsets to
  2796 + * ignore e1000e MSI messages, which means we need to test our MSI
  2797 + * interrupt now
  2798 + */
  2799 + {
  2800 + err = e1000_test_msi(adapter);
  2801 + if (err) {
  2802 + e_err("Interrupt allocation failed\n");
  2803 + goto err_req_irq;
  2804 + }
  2805 + }
2654 2806  
2655 2807 /* From here on the code is the same as e1000e_up() */
2656 2808 clear_bit(__E1000_DOWN, &adapter->state);