Refactor Makefile.am to move common files from 3 libraries into a single variable.
[debian/gnuradio] / usrp2 / firmware / lib / ethernet.c
index 0e2f461672d0dc6326e16430a25eafc1fe7f2ee6..f554e0179cabbf9e47ea52b667e27a6223c51ebb 100644 (file)
@@ -43,6 +43,8 @@ ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_cal
 static void
 ed_set_mac_speed(int speed)
 {
+  printf("Speed set to %d\n",speed);
+  /*
   switch(speed){
   case 10:
     eth_mac->speed = 1;
@@ -56,6 +58,7 @@ ed_set_mac_speed(int speed)
   default:
     break;
   }
+  */
 }
 
 static void
@@ -86,6 +89,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 +156,8 @@ ed_check_phy_state(void)
       new_speed = S_UNKNOWN;
       break;
     }
+
+    check_flow_control_resolution();
   }
   else {                               // link's down
     if (VERBOSE)
@@ -164,17 +199,17 @@ ethernet_init(void)
   ed_state.link_speed = S_UNKNOWN;
 
   // initialize MAC registers
-  eth_mac->tx_hwmark = 0x1e;
-  eth_mac->tx_lwmark = 0x19;
+  //  eth_mac->tx_hwmark = 0x1e;
+  //eth_mac->tx_lwmark = 0x19;
 
-  eth_mac->crc_chk_en = 1;
-  eth_mac->rx_max_length = 2048;
+  //eth_mac->crc_chk_en = 1;
+  //eth_mac->rx_max_length = 2048;
 
   // configure PAUSE frame stuff
-  eth_mac->tx_pause_en = 1;            // pay attn to pause frames sent to us
+  //eth_mac->tx_pause_en = 1;          // pay attn to pause frames sent to us
 
-  eth_mac->pause_quanta_set = 38;      // a bit more than 1 max frame 16kb/512 + fudge
-  eth_mac->pause_frame_send_en = 1;    // enable sending pause frames
+  //eth_mac->pause_quanta_set = 38;    // a bit more than 1 max frame 16kb/512 + fudge
+  //eth_mac->pause_frame_send_en = 1;  // enable sending pause frames
 
 
   // setup PHY to interrupt on changes
@@ -194,9 +229,40 @@ 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);
+  int r = eth_mac_miim_read(PHY_AUTONEG_ADV);                  // DEBUG, read back
+  if (t != r){
+    printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r);
+  }
 
   // Restart autonegotation.  
   // We want to ensure that we're advertising our PAUSE capabilities.
@@ -263,6 +329,7 @@ ethernet_check_errors(void)
   // these registers are reset when read
   
   int  r = 0;
+  /*
   if (eth_mac_read_rmon(0x05) != 0)
     r |= RME_RX_CRC;
   if (eth_mac_read_rmon(0x06) != 0)
@@ -276,6 +343,6 @@ ethernet_check_errors(void)
     r |= RME_TX_FIFO_UNDER;
   if (eth_mac_read_rmon(0x27) != 0)
     r |= RME_TX_FIFO_OVER;
-
+  */
   return r;
 }