From d2baf9d612e1a35645079eb582ad5a6c5881377e Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 3 Mar 2014 12:23:23 -0800 Subject: BUG #371: X300: Dies and left in bad state - Disabled packet forwarding and link state cycle detection in firmware. - Fixed the link state algorithm so the updating runs the first time and the forwading update only happens when necessary. - Added check for 10GbE before calling MDIO functions. --- firmware/x300/lib/ethernet.c | 90 ++++++++++++++++++++++-------------------- firmware/x300/x300/x300_init.c | 4 +- firmware/x300/x300/x300_main.c | 23 +++++++---- 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/firmware/x300/lib/ethernet.c b/firmware/x300/lib/ethernet.c index fdde9e41b..7a86980c7 100644 --- a/firmware/x300/lib/ethernet.c +++ b/firmware/x300/lib/ethernet.c @@ -82,7 +82,7 @@ ethernet_ninterfaces(void) // Clause 45 MDIO used for 10Gig Ethernet has two bus transactions to complete a transfer. // An initial transaction sets up the address, and a subsequent one transfers the read or write data. // -static uint32_t +static uint32_t xge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port) { // Set register address each iteration @@ -103,9 +103,9 @@ xge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t device return(xge_regs->mdio_data); } -static void +static void xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port, const uint32_t data) -{ +{ // Set register address each iteration xge_regs->mdio_addr = address; // Its a clause 45 device. We want to ADDRESS @@ -114,13 +114,13 @@ xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t devic xge_regs->mdio_control = 1; // Wait until bus transaction complete while (xge_regs->mdio_control == 1); - // Write new value to mdio_write_data reg. - xge_regs->mdio_data = data; - // Its a clause 45 device. We want to WRITE + // Write new value to mdio_write_data reg. + xge_regs->mdio_data = data; + // Its a clause 45 device. We want to WRITE xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_WRITE) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); - // Start MDIO bus transaction - xge_regs->mdio_control = 1; - // Wait until bus transaction complete + // Start MDIO bus transaction + xge_regs->mdio_control = 1; + // Wait until bus transaction complete while (xge_regs->mdio_control == 1); } @@ -128,7 +128,7 @@ xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t devic // // Clause 22 MDIO used for 1Gig Ethernet has one bus transaction to complete a transfer. // -static uint32_t +static uint32_t ge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t port) { // Its a clause 22 device. We want to READ @@ -141,16 +141,16 @@ ge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t port) return(xge_regs->mdio_data); } -static void +static void ge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t port, const uint32_t data) { - // Write new value to mdio_write_data reg. - xge_regs->mdio_data = data; - // Its a clause 22 device. We want to WRITE + // Write new value to mdio_write_data reg. + xge_regs->mdio_data = data; + // Its a clause 22 device. We want to WRITE xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE22) | XGE_MDIO_OP(MDIO_C22_WRITE) | XGE_MDIO_ADDR(port) | address; - // Start MDIO bus transaction - xge_regs->mdio_control = 1; - // Wait until bus transaction complete + // Start MDIO bus transaction + xge_regs->mdio_control = 1; + // Wait until bus transaction complete while (xge_regs->mdio_control == 1); } @@ -205,7 +205,7 @@ xge_i2c_rd(const uint32_t base, const uint8_t i2c_dev_addr, const uint8_t i2c_wo // Now read back a byte of data if (wb_i2c_read(base, i2c_dev_addr, &buf, 1) == false) return(-1); - + return((int) buf); } @@ -334,15 +334,15 @@ xge_phy_init(const uint8_t eth, const uint32_t mdio_port) printf("INFO: Begining XGE PHY init sequence.\n"); // Software reset x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port); - x = x | (1 << 15); - write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); + x = x | (1 << 15); + write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); while(x&(1<<15)) x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port); } void xge_poll_sfpp_status(const uint32_t eth) -{ +{ uint32_t x; // Has MODDET/MODAbS changed since we last looked? x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); @@ -355,14 +355,20 @@ xge_poll_sfpp_status(const uint32_t eth) printf("DEBUG: eth%1d MODABS changed state: %d\n", eth, (x & SFPP_STATUS_MODABS) >> 2); if (x & (SFPP_STATUS_RXLOS_CHG|SFPP_STATUS_TXFAULT_CHG|SFPP_STATUS_MODABS_CHG)) - if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) { - xge_ethernet_init(eth); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + { + if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) + { + if (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1) + { + xge_ethernet_init(eth); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + mdelay(100); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); + mdelay(100); + dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); } + } + } if (x & SFPP_STATUS_MODABS_CHG) { // MODDET has changed state since last checked @@ -383,14 +389,14 @@ xge_poll_sfpp_status(const uint32_t eth) //The link became up, send a GARP so everyone knows our mac/ip association if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth)); } - + void xge_ethernet_init(const uint32_t eth) -{ - xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); - //xge_hard_phy_reset(); - xge_phy_init(eth ,MDIO_PORT); +{ + xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); + //xge_hard_phy_reset(); + xge_phy_init(eth ,MDIO_PORT); uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); printf(" eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d\n", eth, @@ -411,7 +417,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) printf("%x",device); printf(" "); switch(address) { - case XGE_MDIO_CONTROL1: + case XGE_MDIO_CONTROL1: printf("CONTROL1: "); printf("%x",data); printf(" "); for (x=15; x >= 0 ; x--) @@ -423,7 +429,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 11: printf("Low Power Mode,"); break; case 5:case 4:case 3:case 2: printf("RESERVED speed value,"); break; case 0: printf("PMA loopback,"); break; - } //else + } //else // Bits clear. //switch (x) { //case 13: case 6: printf(" None 10Gb/s speed set!"); break; @@ -440,7 +446,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 7: printf("Fault Detected,"); break; case 2: printf("Link is Up,"); break; case 1: printf("Supports Low Power,"); break; - } else + } else // Bits Clear switch(x) { case 2: printf("Link is Down,"); break; @@ -457,7 +463,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 15:case 14:case 13:case 12:case 11:case 10:case 9: case 8:case 7:case 6:case 5:case 4:case 3:case 2:case 1: printf("RESERVED bits set!,"); break; case 0: printf("Capable of 10Gb/s,"); - } else + } else // Bits clear. switch(x) { case 0: printf("Incapable of 10Gb/s,"); break; @@ -572,7 +578,7 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) case 2: printf("Lane 2 not synced,"); break; case 1: printf("Lane 1 not synced,"); break; case 0: printf("Lane 0 not synced,"); break; - } + } printf(" \n"); break; case XILINX_CORE_VERSION: @@ -591,23 +597,23 @@ void decode_reg(uint32_t address, uint32_t device, uint32_t data) } } -void +void dump_mdio_regs(const uint8_t eth, uint32_t mdio_port) { volatile unsigned int x; int y; unsigned int regs_a[9] = {0,1,4,5,6,7,8,32,33}; unsigned int regs_b[10] = {0,1,4,5,6,7,8,10,11,65535}; - + printf("\n"); - for (y = 0; y < 10; y++) + for (y = 0; y < 10; y++) { // Read MDIO data x = read_mdio(eth,regs_b[y],XGE_MDIO_DEVICE_PMA,mdio_port); decode_reg(regs_b[y],XGE_MDIO_DEVICE_PMA,x); } - + for (y = 0; y < 9; y++) { // Read MDIO data diff --git a/firmware/x300/x300/x300_init.c b/firmware/x300/x300/x300_init.c index 2ddfef86b..978168b09 100644 --- a/firmware/x300/x300/x300_init.c +++ b/firmware/x300/x300/x300_init.c @@ -75,7 +75,9 @@ static void init_network(void) pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc); printf("PKT RAM0 BASE 0x%x\n", (&pkt_config)->base); u3_net_stack_init(&pkt_config); - link_state_route_proto_init(); + + //FIXME: Uncomment when feature is required + //link_state_route_proto_init(); //read everything from eeprom static const uint8_t eeprom_cmd[2] = {0, 0}; //the command is 16 bits of address offset diff --git a/firmware/x300/x300/x300_main.c b/firmware/x300/x300/x300_main.c index 5f7c19624..92368ec9c 100644 --- a/firmware/x300/x300/x300_main.c +++ b/firmware/x300/x300/x300_main.c @@ -372,6 +372,12 @@ static void handle_uarts(void) **********************************************************************/ static void update_forwarding(const uint8_t e) { + /* FIXME: This code is broken. + * It blindly enables forwarding without regard to whether or not + * packets can be forwarded. If one of the Ethernet interfaces is not + * connected, data backs up until the first interface becomes unresponsive. + * Uncomment and fix when topologies requiring forwarding are supported. + * //update forwarding rules uint32_t forward = 0; if (!link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) @@ -381,6 +387,7 @@ static void update_forwarding(const uint8_t e) } const uint32_t eth_base = (e == 0)? SR_ETHINT0 : SR_ETHINT1; wb_poke32(SR_ADDR(SET0_BASE, eth_base + 8 + 4), forward); + */ } static void handle_link_state(void) @@ -390,13 +397,9 @@ static void handle_link_state(void) shmem[X300_FW_SHMEM_ROUTE_MAP_ADDR] = (uint32_t)link_state_route_get_node_mapping(&map_len); shmem[X300_FW_SHMEM_ROUTE_MAP_LEN] = map_len; - //update forwarding for all eths - //low overhead: this does not run the algorithm - for (uint8_t e = 0; e < ethernet_ninterfaces(); e++) update_forwarding(e); - static size_t count = 0; - if (count++ < 2000) return; //2 seconds - count = 0; + if (count--) return; + count = 2000; //repeat every ~2 seconds link_state_route_proto_tick(); for (size_t e = 0; e < ethernet_ninterfaces(); e++) @@ -406,7 +409,12 @@ static void handle_link_state(void) link_state_route_proto_update(e); link_state_route_proto_flood(e); } + + //update forwarding if something changed + bool before = link_state_route_proto_causes_cycle_cached(e, (e+1)%2); link_state_route_proto_update_cycle_cache(e); + if (before != link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) + update_forwarding(e); /* printf("is there a cycle %s -> %s? %s\n", ip_addr_to_str(u3_net_stack_get_ip_addr(e)), @@ -437,7 +445,8 @@ int main(void) static const uint32_t tick_delta = CPU_CLOCK/1000; if (ticks_passed > tick_delta) { - handle_link_state(); //deal with router table update + //FIXME: Uncomment when feature is required + //handle_link_state(); //deal with router table update handle_claim(); //deal with the host claim register update_leds(); //run the link and activity leds garp(); //send periodic garps -- cgit v1.2.3