Fixed ticket:339 (ethernet capability advertisement). We now
authoreb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Wed, 18 Mar 2009 20:00:41 +0000 (20:00 +0000)
committereb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Wed, 18 Mar 2009 20:00:41 +0000 (20:00 +0000)
advertise that we only handle 1000BASE-T, and that we want to send
PAUSE frames, but not receive them.  The flow control resolution is
currently printed out on the serial port when the link comes up.  When
we get what we want, it says "ethernet flow control: WE_TX".  If it
says "ethernet flow control: NONE" unthrottled transmission (e.g.,
usrp2_siggen.py) will be hosed.

git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10634 221aa14e-8319-0410-a670-987f0aec2ac5

usrp2/firmware/lib/ethernet.c
usrp2/firmware/lib/ethernet.h

index 0e2f461672d0dc6326e16430a25eafc1fe7f2ee6..d19287044b5bdea518e97d974988594b40e09422 100644 (file)
@@ -86,6 +86,36 @@ ed_link_speed_change(int speed)
   ed_link_up(speed);
 }
 
+static void
+print_flow_control(int flow_control)
+{
+  static const char *flow_control_msg[4] = {
+    "NONE", "WE_TX", "WE_RX", "SYMMETRIC"
+  };
+  putstr("ethernet flow control: ");
+  puts(flow_control_msg[flow_control & 0x3]);
+}
+
+static void
+check_flow_control_resolution(void)
+{
+  static const unsigned char table[16] = {
+    // index = {local_asm, local_pause, partner_asm, partner_pause}
+    FC_NONE,  FC_NONE,  FC_NONE,  FC_NONE,
+    FC_NONE,  FC_SYMM,  FC_NONE,  FC_SYMM,
+    FC_NONE,  FC_NONE,  FC_NONE,  FC_WE_TX,
+    FC_NONE,  FC_SYMM,  FC_WE_RX, FC_SYMM
+  };
+
+  int us = eth_mac_miim_read(PHY_AUTONEG_ADV);
+  int lp = eth_mac_miim_read(PHY_LP_ABILITY);
+  int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3);
+  ed_state.flow_control = table[index];
+
+  if (1)
+    print_flow_control(ed_state.flow_control);
+}
+
 /*
  * Read the PHY state register to determine link state and speed
  */
@@ -123,6 +153,8 @@ ed_check_phy_state(void)
       new_speed = S_UNKNOWN;
       break;
     }
+
+    check_flow_control_resolution();
   }
   else {                               // link's down
     if (VERBOSE)
@@ -194,9 +226,36 @@ ethernet_init(void)
 
   pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
 
-  // Advertise that we handle PAUSE frames and asymmetric pause direction.
+  // Advertise our flow control configuation.
+  //
+  // We and the link partner each specify two bits in the base page
+  // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR.
+  // The bits say what a device is "willing" to do, not what may actually
+  // happen as a result of the negotiation.  There are 4 cases:
+  //
+  // PAUSE  ASM_DIR
+  //
+  //  0        0        I have no flow control capability.
+  //
+  //  1        0        I both assert and respond to flow control.
+  //
+  //  0        1        I assert flow control, but cannot respond.  That is,
+  //                    I want to be able to send PAUSE frames, but will ignore any
+  //                   you send to me.  (This is our configuration.)
+  //
+  //  1        1        I can both assert and respond to flow control AND I am willing
+  //                    to operate symmetrically OR asymmetrically in EITHER direction.
+  //                    (We hope the link partner advertises this, otherwise we don't
+  //                   get what we want.)
+
   int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
-  eth_mac_miim_write(PHY_AUTONEG_ADV, t | NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
+  t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
+  t |= NWAY_AR_ASM_DIR;
+
+  // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex
+  t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS);
+
+  eth_mac_miim_write(PHY_AUTONEG_ADV, t);
 
   // Restart autonegotation.  
   // We want to ensure that we're advertising our PAUSE capabilities.
index 4e549046018b111e7bc6520720ebdc72716f8f87..aaed05d4483fd0d7d177979960db8fc7221b75b2 100644 (file)
@@ -65,11 +65,18 @@ int ethernet_check_errors(void);
 
 typedef enum { LS_UNKNOWN, LS_DOWN, LS_UP } eth_link_state_t;
 
+// flow control bitmasks
+#define        FC_NONE         0x0
+#define        FC_WE_TX        0x1                     // we send PAUSE frames
+#define        FC_WE_RX        0x2                     // we honor received PAUSE frames
+#define        FC_SYMM         (FC_WE_TX | FC_WE_RX)
+
 #define S_UNKNOWN (-1)                 // unknown link speed
 
 typedef struct {
   eth_link_state_t     link_state;
   int                  link_speed;     // in Mb/s
+  int                  flow_control;
 } ethernet_t;
 
 #endif /* INCLUDED_ETHERNET_H */