e1000e: Separate signaling for link check/link up
authorBenjamin Poirier <bpoirier@suse.com>
Fri, 21 Jul 2017 18:36:26 +0000 (11:36 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 3 Mar 2018 15:50:54 +0000 (15:50 +0000)
commitac8f81b0f33b6264fa60163ca2510e7af2ec38bb
treebb5bfc54af35369613658ac7c439868be328520e
parenta36af0bf619c90274a11c518437c306fdaed4279
e1000e: Separate signaling for link check/link up

commit 19110cfbb34d4af0cdfe14cd243f3b09dc95b013 upstream.

Lennart reported the following race condition:

\ e1000_watchdog_task
    \ e1000e_has_link
        \ hw->mac.ops.check_for_link() === e1000e_check_for_copper_link
            /* link is up */
            mac->get_link_status = false;

                            /* interrupt */
                            \ e1000_msix_other
                                hw->mac.get_link_status = true;

        link_active = !hw->mac.get_link_status
        /* link_active is false, wrongly */

This problem arises because the single flag get_link_status is used to
signal two different states: link status needs checking and link status is
down.

Avoid the problem by using the return value of .check_for_link to signal
the link status to e1000e_has_link().

Reported-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
[bwh: Backported to 3.2: adjust filename]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/net/ethernet/intel/e1000e/lib.c
drivers/net/ethernet/intel/e1000e/netdev.c