diff --git a/rtl837x_common.h b/rtl837x_common.h index 68ebe3d..d47bede 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -72,18 +72,9 @@ struct vlan_tag { #define RTL_FRAME_TAG_ID 0x8899 #define RTL_FRAME_TAG_VERSION 0x04 -struct rtl_frame_desc { - uint8_t padding[VLAN_TAG_SIZE]; // Pad to the size of a RTL-VLAN tag or dot1q-tag - uint8_t tx_seq; - uint8_t chksum_flags; // 0x7 enables Checksums for frame header, L2 and L3 - uint8_t reserved_1 [2]; - uint16_t len; // Length is Little Endian - uint8_t reserved_2 [2]; -}; - // For TX, an 8 byte (plus 4 byte padding when when VLAN is enabled) // header describing the frame to be moved to the Asic is used -#define RTL_FRAME_DESC_SIZE (sizeof (struct rtl_frame_desc)) +#define RTL_FRAME_DESC_SIZE 12 // This is the standard size of an Ethernet frame header #define ETHER_HEADER_SIZE 14 diff --git a/rtlplayground.c b/rtlplayground.c index 9910785..6f35f19 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -15,6 +15,7 @@ #include "rtl837x_igmp.h" #include "rtl837x_leds.h" #include "rtl837x_bandwidth.h" +#include "rtl837x_init.h" #include "dhcp.h" #include "cmd_parser.h" #include "cmd_editor.h" @@ -140,8 +141,52 @@ __xdata bool button_last; __xdata uint8_t button_sec_counter_last; volatile __bit tx_buf_empty; +struct eth_in { + struct uip_eth_addr dst; + struct uip_eth_addr src; + struct rtl_tag rtl_tag; + struct vlan_tag vlan_tag; + u16_t ether_type; +}; + +struct rtl_dot1q_frame { + union { + struct { + uint8_t tx_seq; + uint8_t chksum_flags; // 0x7 enables Checksums for frame header, L2 and L3 + uint8_t reserved_1 [2]; + uint16_t len; // Length is Little Endian + uint8_t reserved_2 [2]; + struct uip_eth_addr dst; + struct uip_eth_addr src; + uint16_t tpid; + uint16_t tci; + } q_frame; + struct { + uint8_t padding[VLAN_TAG_SIZE]; // Pad to the size of a RTL-VLAN tag or dot1q-tag + uint8_t tx_seq; + uint8_t chksum_flags; // 0x7 enables Checksums for frame header, L2 and L3 + uint8_t reserved_1 [2]; + uint16_t len; // Length is Little Endian + uint8_t reserved_2 [2]; + struct uip_eth_addr dst; + struct uip_eth_addr src; + } nonq_frame; + }; +}; + +// Dot 1Q tag size is the size of tpid + tci +#define DOT_1Q_TAG_SIZE 4 + +#define ETH_IN ((__xdata struct eth_in *)&uip_buf[0]) #define ETHERTYPE_OFFSET (12 + VLAN_TAG_SIZE + RTL_TAG_SIZE) +// The output frame structure with initial frame descriptor including padding +#define FRAME (((__xdata struct rtl_dot1q_frame *)&uip_buf[0])->nonq_frame) + +// The output frame structure with 802.1Q field and the padding moved before the buffer-start +#define FRAME_Q (((__xdata struct rtl_dot1q_frame *)&uip_buf[-VLAN_TAG_SIZE])->q_frame) + void isr_timer0(void) __interrupt(1) { } @@ -558,15 +603,38 @@ void nic_rx_packet(register uint16_t buffer, register uint16_t ring_ptr) */ void nic_tx_packet(uint16_t ring_ptr) { -// uint16_t buffer = (uint16_t) tx_buf; - uint16_t buffer = (uint16_t) uip_buf + VLAN_TAG_SIZE; - SFR_NIC_DATA_U16LE = buffer; - + uint16_t len; + + /* If we have a management VLAN, we have inserted a dot1Q-tag into the frame and + * the frame starts at the beginning of uip_buf with the RTL TX descriptor, + * otherwise the frame is a normal Ethernet frame which starts with + * an RTL TX descriptor being padded at the beginning, in the second case + * we need to skip the padding for the sending of the frame. + */ + if (management_vlan) { + SFR_NIC_DATA_U16LE = (uint16_t) uip_buf; + len = FRAME_Q.len; + /* + (__xdata struct rtl_dot1q_frame *)uip_buf +#define FRAME (((__xdata struct rtl_dot1q_frame *)&uip_buf[0]).nonq_frame)*/ + } else { + SFR_NIC_DATA_U16LE = (uint16_t) uip_buf + VLAN_TAG_SIZE; + len = FRAME.len; + } + +#ifdef RXTXDBG + print_string("TX: \n"); + for (uint8_t i = 0; i < 100; i++) { + print_byte(uip_buf[i]); + write_char(' '); + } + write_char('\n'); +#endif + ring_ptr <<= 3; ring_ptr |= 0x8000; SFR_NIC_RING_U16LE = ring_ptr; - - uint16_t len = (((uint16_t)uip_buf[VLAN_TAG_SIZE + 5]) << 8) | uip_buf[VLAN_TAG_SIZE + 4]; + len += 0xf; len >>= 3; SFR_NIC_CTRL = len; @@ -924,26 +992,27 @@ uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) void tcpip_output(void) { // Add TX-TAG - uip_buf[VLAN_TAG_SIZE] = tx_seq++; - uip_buf[VLAN_TAG_SIZE + 1] = 0x07; // Enable all checksums - uip_buf[VLAN_TAG_SIZE + 5] = uip_len >> 8; - uip_buf[VLAN_TAG_SIZE + 4] = uip_len; - uip_buf[VLAN_TAG_SIZE + 2] = uip_buf[VLAN_TAG_SIZE + 3] = 0; - uip_buf[VLAN_TAG_SIZE + 6] = uip_buf[VLAN_TAG_SIZE + 7] = 0; + FRAME.tx_seq = tx_seq++; + FRAME.chksum_flags = 0x07; // Enable all checksums + FRAME.reserved_1[0] = 0x00; FRAME.reserved_1[1] = 0x00; + FRAME.len = uip_len; + FRAME.reserved_2[0] = 0x00; FRAME.reserved_2[1] = 0x00; + + // For the management VLAN we insert an 802.1Q VLAN tag + if (management_vlan) { + // Shift the ethernet header before the HW type including the rtl_frame_desc to the beginning of uip_buf + // to allow space to insert the dot 1Q tag + for (uint8_t i = 0; i < sizeof(struct rtl_dot1q_frame) - (VLAN_TAG_SIZE * 2); i++) + uip_buf[i] = uip_buf[i + DOT_1Q_TAG_SIZE]; + FRAME_Q.len += DOT_1Q_TAG_SIZE; + FRAME_Q.tpid = HTONS(0x8100); // Change ether-type to Dot1Q + FRAME_Q.tci = HTONS(management_vlan); + } reg_read_m(RTL837X_REG_CPU_TX_CURR_PKT); uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8; ring_ptr |= sfr_data[3]; -#ifdef RXTXDBG - print_string("TX: \n"); - for (uint8_t i = 0; i < 120; i++) { - print_byte(uip_buf[i]); - write_char(' '); - } - write_char('\n'); -#endif - // Move data over from xmem buffer to ASIC side using DMA nic_tx_packet(ring_ptr); @@ -987,10 +1056,8 @@ void handle_rx(void) REG_SET(RTL837X_REG_NIC_RXCMD, 1); uip_len = (((uint16_t)rx_headers[5]) << 8) | rx_headers[4]; - // Retrieve VLAN from VLAN-tag - rx_packet_vlan = uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 2] & 0xf; - rx_packet_vlan <<= 8; - rx_packet_vlan |= uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 3]; + rx_packet_vlan = NTOHS(ETH_IN->vlan_tag.vlan) & 0x0fff; + #ifdef RXTXDBG print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n'); print_string(" RX dst: "); print_byte(uip_buf[0]); print_byte(uip_buf[1]); print_byte(uip_buf[2]); @@ -1009,12 +1076,12 @@ void handle_rx(void) if (uip_len) { tcpip_output(); } - } else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x06) { // ARP? + } else if (ETH_IN->ether_type == HTONS(0x0806)) { // ARP uip_arp_arpin(); if (uip_len) { tcpip_output(); } - } else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x00) { // TCP? + } else if (ETH_IN->ether_type == HTONS(0x0800)) { // IPv4 if (!management_vlan || management_vlan == rx_packet_vlan) { uip_arp_ipin(); // Learn MAC addresses in TCP packets uip_input(); @@ -1537,78 +1604,6 @@ void nic_setup(void) } -/* - * Configure the PHY-Side of the SDS-SDS link between SoC and PHY - */ -void sds_init(void) -{ -/* - p001e.000d:9535 R02f8-00009535 R02f4-0000953a P000001.1e00000d:953a - p001e.000d:953a p001e.000d:953a R02f8-0000953a R02f4-00009530 P000001.1e00000d:9530 - - RTL8373: - p001e.000d:0010 R02f8-00000010 R02f4-0000001a P000001.1e00000d:b7fe - p001e.000d:0010 p001e.000d:0010 R02f8-00000010 R02f4-00000010 P000001.1e00000d:b7fe -*/ - phy_read(0, PHY_MMD30, 0xd); - uint16_t pval = SFR_DATA_U16; - - // PHY Initialization: - REG_WRITE(0x2f8, 0, 0, pval >> 8, pval); - delay(20); - - pval &= 0xfff0; - pval |= 0x0a; - REG_WRITE(0x2f4, 0, 0, pval >> 8, pval); - delay(10); - - phy_write_mask(0x1, PHY_MMD30, 0xd, pval); - - phy_read(0, PHY_MMD30, 0xd); - pval = SFR_DATA_U16; - - REG_WRITE(0x2f8, 0, 0, pval >> 8, pval); - - pval &= 0xfff0; - REG_WRITE(0x2f4, 0, 0, pval >> 8, pval); - - phy_write_mask(0x1, PHY_MMD30, 0xd, pval); - - if (machine_detected.isN) { - uint16_t pval; - - print_string(" N-settings"); - // Serdes 0 RX PN swap for 64B/66B - sds_read(1, 6, 2); - pval = SFR_DATA_U16; - sds_write_v(1, 6, 2, pval | 0x2000); - - // Serdes 1 RX PN swap for 8B/10B - sds_read(1, 0, 0); - pval = SFR_DATA_U16; - sds_write_v(1, 0, 0, pval | 0x200); - - // Serdes 0 RX PN swap for 64B/66B - sds_read(0, 6, 2); - pval = SFR_DATA_U16; - sds_write_v(0, 6, 2, pval | 0x2000); - - if (machine_detected.isRTL8373) { - // RTL8224: Serdes 0 RX PN swap for 64B/66B - // We assume that RTL8373N always paired with RTL8224N. - // This sds register value is 0x0000 at reset. - // So only write to it. - RTL8224_SDS_WRITE(0, 6, 2, 0x2000); - } else { - // Serdes 0 RX PN swap for 8B/10B - sds_read(0, 0, 0); - pval = SFR_DATA_U16; - sds_write_v(0, 0, 0, pval | 0x200); - } - } -} - - void set_sys_led_state(uint8_t state) { reg_read_m(RTL837X_REG_LED_MODE); @@ -1630,167 +1625,6 @@ void rtl8373_revision(void) } -void rtl8373_init(void) -{ - print_string("\nrtl8373_init called\n"); - - // r65d8:3ffbedff R65d8-3ffbedff - reg_bit_set(0x65d8, 0x1d); - - sds_init(); - // Disable all SERDES for configuration - REG_SET(RTL837X_REG_SDS_MODES, 0x000037ff); - - // q000601:c800 Q000601:c804 q000601:c804 Q000601:c800 - sds_read(0, 0x06, 0x01); - uint16_t pval = SFR_DATA_U16; - sds_write_v(0, 0x06, 0x01, pval | 0x04); - delay(50); - sds_read(0, 0x06, 0x01); - pval = SFR_DATA_U16; - sds_write_v(0, 0x06, 0x01, pval & 0xfffb); - - phy_config_8224(); - sds_config_mac(1, SDS_OFF); // Off for now until SFP+ port used - sds_config_mac(2, SDS_SGMII); // For RTL8224 - sds_config(0, SDS_QXGMII); - - // SDS 1 setup - // q012100:4902 Q012100:4906 q013605:0000 Q013605:4000 Q011f02:001f q011f15:0086 - sds_write_v(1, 0x21, 0x00, 0x4906); - sds_write_v(1, 0x36, 0x05, 0x4000); - sds_write_v(1, 0x1f, 0x02, 0x001f); - sds_read(1, 0x1f, 0x15); - pval = SFR_DATA_U16; - - // r0a90:000000f3 R0a90-000000fc - reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE); - sfr_mask_data(0, 0x0f,0x0c); - reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE); - - if (machine_detected.isN) { - print_string(" TX_POLARITY_SWAP\n"); - // FOR N-Version: #TX_POLARITY_SWAP - reg_read_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP); - sfr_data[2] = 0x59; - sfr_data[3] = 0x6a; - reg_write_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP); - } - - rtl8224_phy_enable(); - - // Disable PHYs for configuration - phy_write_mask(0xff,PHY_MMD31,0xa610,0x2858); - - // Set bits 0x13 and 0x14 of 0x5fd4 - // r5fd4:0002914a R5fd4-001a914a - reg_bit_set(0x5fd4, 0x13); - reg_bit_set(0x5fd4, 0x14); - - // Configure ports - uint16_t reg = 0x1238; // Port base register for the bits we set - for (char i = 0; i < 9; i++) { - // Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag - REG_SET(reg, 0xe77); - reg += 0x100; - } - - // r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031 - reg_bit_set(0xb7c, 5); - - // R7124-00001050 R7128-00001050 R712c-00001050 R7130-00001050 R7134-00001050 R7138-00001050 - // R713c-00001050 R7140-00001050 R7144-00001050 R7148-00001050 - REG_SET(0x7124, 0x1050); REG_SET(0x7128, 0x1050); REG_SET(0x712c, 0x1050); - REG_SET(0x7130, 0x1050); REG_SET(0x7134, 0x1050); REG_SET(0x7138, 0x1050); - REG_SET(0x713c, 0x1050); REG_SET(0x7140, 0x1050); REG_SET(0x7144, 0x1050); - REG_SET(0x7148, 0x1050); - - reg_bit_set(RTL837X_REG_HW_CONF, 0); - - // enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs - port_eee_enable_all(EEE_2G5 | EEE_NORESET); - - // TODO: patch the PHYs - - // Re-enable PHY after configuration - phy_write_mask(0xff,PHY_MMD31,0xa610,0x2058); - - // Enables MAC access - // Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init - // r632c:00000540 R632c-001f8540 // RTL8373: 001ff540 - reg_read_m(0x632c); - sfr_mask_data(1, 0x70, 0xf0); // The ports of the RTL8824 - sfr_mask_data(2, 0x10, 0x1f); - reg_write_m(0x632c); - - print_string("\nrtl8373_init done\n"); -} - - -void rtl8372_init(void) -{ - print_string("\nrtl8372_init called\n"); - - sds_init(); - phy_config(8); // PHY configuration: External 8221B? - phy_config(3); // PHY configuration: all internal PHYs? - // Set the MAC SerDes Modes Bits 0-4: SDS 0 = 0x2 (0x2), Bits 5-9: SDS 1: 1f (off) - // r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003e2 r7b20:000003e2 R7b20-000003e2 - reg_read_m(RTL837X_REG_SDS_MODES); - sfr_mask_data(1, 0, 0x03); - sfr_mask_data(0, 0, 0xe2); - reg_write_m(RTL837X_REG_SDS_MODES); - - // r0a90:000000f3 R0a90-000000fc - reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE); - sfr_mask_data(0, 0x0f, 0x0c); - reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE); - - // Disable PHYs for configuration - phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2858); - - // Set bits 0x13 and 0x14 of 0x5fd4 - // r5fd4:0002914a R5fd4-001a914a - reg_bit_set(0x5fd4, 0x13); - reg_bit_set(0x5fd4, 0x14); - - // Configure ports 3-8: - // - // r1538:00000e33 R1538-00000e37 r1538:00000e37 R1538-00000e37 r1538:00000e37 R1538-00000f37 - // [...] - /// - uint16_t reg = 0x1238 + 0x300; // Port base register for the bits we set - for (char i = machine.min_port; i <= machine.max_port; i++) { - // Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag - REG_SET(reg, 0xe77); - reg += 0x100; - } - - // r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031 - reg_bit_set(0xb7c, 5); - - reg_bit_set(RTL837X_REG_HW_CONF, 0); - - - // enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs - port_eee_enable_all(EEE_2G5 | EEE_NORESET); - - // TODO: patch the PHYs - - // Re-enable PHY after configuration - phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2058); - - // Enables MAC access - // Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init - // r632c:00000540 R632c-001f8540 // RTL8373: 001ff540 - reg_read_m(0x632c); - sfr_mask_data(1, 0x70, 0x80); - sfr_mask_data(2, 0x10, 0x1f); - reg_write_m(0x632c); - print_string("\nrtl8372_init done\n"); -} - - /* * The SoC manages Link-State for steering the LEDs and can set PHY-settings * automatically through Realtek's SMI (Simple Managagement) Interface, a