mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Compare commits
25
Commits
d3f1069285
...
434acbcc13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
434acbcc13 | ||
|
|
1aae2fac30 | ||
|
|
1f9b3df3e6 | ||
|
|
5a2c4ca029 | ||
|
|
63e367d298 | ||
|
|
5e513daf17 | ||
|
|
b42eace21d | ||
|
|
3dfd6a88c7 | ||
|
|
7fa26e0ae3 | ||
|
|
1c8cdab4bf | ||
|
|
f49ca0d6fe | ||
|
|
12fb6fd809 | ||
|
|
dad65fd550 | ||
|
|
dc82e044bc | ||
|
|
7daa9effe0 | ||
|
|
950586135a | ||
|
|
c1ad800fc5 | ||
|
|
dc4fb5becc | ||
|
|
78ecef15e9 | ||
|
|
eab927f52a | ||
|
|
02c816647c | ||
|
|
624f93a28a | ||
|
|
6616a0c9ce | ||
|
|
d6d9c368e9 | ||
|
|
36de9791be |
No files matched your search
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt update
|
||||
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev -y
|
||||
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y
|
||||
- name: Check if machine.c can be compiled for all machines
|
||||
run: make machine_check
|
||||
- name: Make project
|
||||
|
||||
@@ -59,6 +59,8 @@ SRCS = \
|
||||
dhcp.c \
|
||||
html_data.c \
|
||||
rtlplayground.c \
|
||||
boot.c \
|
||||
sfp.c \
|
||||
syslog.c \
|
||||
udp_apps.c
|
||||
|
||||
@@ -132,7 +134,7 @@ $(BUILDDIR)/%.rel: %.asm | create_build_dir
|
||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||
|
||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
||||
|
||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||
objcopy --input-target=ihex -O binary $< $@
|
||||
|
||||
@@ -59,7 +59,7 @@ device simulator is provided, which runs entirely under Linux as a local webserv
|
||||
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
|
||||
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
|
||||
```
|
||||
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev
|
||||
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev
|
||||
```
|
||||
|
||||
<details>
|
||||
@@ -175,7 +175,7 @@ Header checksum is: 0x5a1
|
||||
## (3) Sandbox Usage with Ghidra (optional)
|
||||
|
||||
You can play with the image using ghidra or flash real Switch Hardware. For
|
||||
ghidra see this information about [Ghidra images](ghidra.md).
|
||||
ghidra see this information about [Ghidra images](doc/ghidra.md).
|
||||
|
||||
## (4) Installation through the Web interface (software way)
|
||||
|
||||
|
||||
@@ -0,0 +1,480 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include <8051.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_init.h"
|
||||
#include "machine.h"
|
||||
#include "phy.h"
|
||||
#include "boot.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint8_t tx_seq;
|
||||
extern __code uint8_t * __code hex;
|
||||
|
||||
|
||||
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode) __banked
|
||||
{
|
||||
reg_read_m(RTL837X_REG_SDS_MODES);
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = 0;
|
||||
switch (sds) {
|
||||
case 0:
|
||||
sfr_mask_data(0, 0x1f, mode);
|
||||
break;
|
||||
case 1:
|
||||
sfr_mask_data(0, 0xe0, mode << 5);
|
||||
sfr_mask_data(1, 0x03, mode >> 3);
|
||||
break;
|
||||
case 2:
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
}
|
||||
if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
else
|
||||
sfr_data[2] &= 0x03;
|
||||
reg_write_m(RTL837X_REG_SDS_MODES);
|
||||
print_string("\nRTL837X_REG_SDS_MODES: ");
|
||||
print_reg(RTL837X_REG_SDS_MODES);
|
||||
print_string("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void early_boot_handle_button(void) __banked
|
||||
{
|
||||
if (machine.reset_pin == GPIO_NA)
|
||||
return;
|
||||
|
||||
gpio_input_setup(machine.reset_pin);
|
||||
|
||||
// Debounce after init
|
||||
delay(100);
|
||||
// If the button is not already held at boot, continue normally.
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
print_string("\n[Reset button held at boot]\n");
|
||||
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms
|
||||
const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms
|
||||
__xdata uint32_t start_ticks = ticks;
|
||||
__xdata uint32_t last_blink_step = start_ticks;
|
||||
__xdata uint8_t blink_step = 0;
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
while (!gpio_pin_test(machine.reset_pin)) {
|
||||
__xdata uint32_t held_ticks = ticks - start_ticks;
|
||||
|
||||
if (held_ticks > max_hold_ticks) {
|
||||
print_string("[Button held >30s at boot; continuing normal boot]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Double blink pattern while button is held:
|
||||
// ON (100ms), OFF (100ms), ON (100ms), OFF (500ms)
|
||||
__xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks;
|
||||
if ((ticks - last_blink_step) >= step_ticks) {
|
||||
blink_step = (blink_step + 1) & 0x3;
|
||||
set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF);
|
||||
last_blink_step = ticks;
|
||||
}
|
||||
|
||||
PCON |= 1;
|
||||
}
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
if ((ticks - start_ticks) >= min_hold_ticks) {
|
||||
print_string("[Button held 10s-30s at boot; restoring default config]\n");
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
flash_default_config();
|
||||
delay(3UL * SYS_TICK_HZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure the SerDes of the SoC for a particular mode
|
||||
* to connect to an SFP module or a PHY
|
||||
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
|
||||
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
|
||||
* SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
|
||||
*/
|
||||
void sds_config(uint8_t sds, uint8_t mode) __banked
|
||||
{
|
||||
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
|
||||
sds_config_mac(sds, mode);
|
||||
|
||||
if (mode == SDS_10GR || mode == SDS_QXGMII)
|
||||
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
|
||||
else
|
||||
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
|
||||
sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400
|
||||
sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02
|
||||
sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e
|
||||
sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002
|
||||
sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390
|
||||
sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f
|
||||
|
||||
uint8_t page = 0;
|
||||
uint16_t v = 0;
|
||||
|
||||
switch (mode) {
|
||||
case SDS_SGMII:
|
||||
case SDS_1000BX_FIBER:
|
||||
v = 0x0300;
|
||||
page = 0x24;
|
||||
break;
|
||||
case SDS_HISGMII:
|
||||
case SDS_HSG:
|
||||
v = 0x0200;
|
||||
page = 0x28;
|
||||
break;
|
||||
case SDS_10GR:
|
||||
case SDS_QXGMII:
|
||||
v = 0x0200;
|
||||
page = 0x2e;
|
||||
break;
|
||||
case SDS_100FX:
|
||||
v = 0x0200;
|
||||
page = 0x26;
|
||||
break;
|
||||
default:
|
||||
print_string("Error in SDS Mode\n");
|
||||
return;
|
||||
}
|
||||
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
|
||||
|
||||
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
|
||||
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
|
||||
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c
|
||||
sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217
|
||||
sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40
|
||||
sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1
|
||||
} else {
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080
|
||||
sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c
|
||||
sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217
|
||||
sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50
|
||||
sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG !
|
||||
}
|
||||
|
||||
sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443
|
||||
sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0
|
||||
|
||||
sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078
|
||||
sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401
|
||||
sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401
|
||||
sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401
|
||||
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
|
||||
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
|
||||
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
|
||||
|
||||
// RTL8261BE
|
||||
if (machine.n_10g && mode == SDS_QXGMII) {
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
return;
|
||||
}
|
||||
if (mode != SDS_QXGMII)
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
|
||||
if (mode == SDS_1000BX_FIBER) {
|
||||
sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020
|
||||
sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0
|
||||
sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d
|
||||
sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void rtl8224_enable(void) __banked
|
||||
{
|
||||
// Set Pin 4 low
|
||||
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
// Configure Pin as output
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
||||
delay(100);
|
||||
// Set pin 4 high
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void nic_setup(void) __banked
|
||||
{
|
||||
// Enable NIC
|
||||
// r6040:00000100 R6040-00001100
|
||||
reg_bit_set(RTL837X_REG_HW_CONF, 0xc);
|
||||
|
||||
// This sets the size of the RX buffer, the filling level is in 0x7874
|
||||
// R7848-000004ff
|
||||
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
|
||||
|
||||
// R7844-000007fe
|
||||
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
|
||||
|
||||
// Configure NIC RX to receive various types of packets
|
||||
// RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17
|
||||
reg_read_m(RTL837X_REG_RX_CTRL);
|
||||
sfr_mask_data(3, 0xff, 0x04);
|
||||
sfr_mask_data(2, 0x03, 0);
|
||||
reg_write_m(RTL837X_REG_RX_CTRL);
|
||||
|
||||
// Enable NIC TX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_TX_CTRL, 0);
|
||||
|
||||
// Enable NIC RX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_RX_CTRL, 0);
|
||||
|
||||
// Drop packets with invalid CRC
|
||||
reg_bit_clear(RTL837X_REG_RX_CTRL, 2);
|
||||
|
||||
// R603c-00000200
|
||||
// CPU-port is CPU-Tag aware (bit 9)
|
||||
REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200);
|
||||
|
||||
// Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9)
|
||||
reg_read_m(RTL837X_REG_CPU_TAG);
|
||||
sfr_mask_data(0, 1, 1);
|
||||
sfr_mask_data(1, 3, 0);
|
||||
reg_write_m(RTL837X_REG_CPU_TAG);
|
||||
|
||||
// Force MAC mode of the CPU port (port 9)
|
||||
// r6368:00000194 R6368-00000197
|
||||
reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4);
|
||||
sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link
|
||||
reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4);
|
||||
|
||||
// Sequence number of TX packets
|
||||
tx_seq = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rtl8373_revision(void) __banked
|
||||
{
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
delay(50);
|
||||
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n');
|
||||
sfr_mask_data(2, 0x0a, 0x00); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The SoC manages Link-State for steering the LEDs and can set PHY-settings
|
||||
* automatically through Realtek's SMI (Simple Managagement) Interface, a
|
||||
* proprietary version of MDIO which for example allows for more PHYs on the same
|
||||
* bus.
|
||||
* Configure polling via SMI and the interface setup during boot.
|
||||
*/
|
||||
void init_smi(void) __banked
|
||||
{
|
||||
print_string("\ninit_switch called\n");
|
||||
|
||||
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
|
||||
* which are at port 8 and additionally at port 3 for a dual SFP device
|
||||
*/
|
||||
|
||||
// Default: 0x00005555
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x5555;
|
||||
if (machine.n_10g == 2) {
|
||||
// 0x00015555, only change the bytes that differs from the default.
|
||||
SFR_DATA_16 = 0x01;
|
||||
} else if (machine.n_sfp == 2)
|
||||
// 0x00005515
|
||||
SFR_DATA_0 = 0x15;
|
||||
reg_write(RTL837X_REG_SMI_MAC_TYPE);
|
||||
|
||||
// Configure polling of all PHYs by the MAC to detect link-state changes
|
||||
// Default: 0x000000ff
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x00ff;
|
||||
if (!machine_detected.isRTL8373) {
|
||||
if (machine.n_sfp == 2) {
|
||||
// 0x000000f0, only change the bytes that differs from the default.
|
||||
SFR_DATA_0 = 0xf0;
|
||||
} else {
|
||||
// 0x000001f8, only change the bytes that differs from the default.
|
||||
SFR_DATA_8 = 0x01;
|
||||
SFR_DATA_0 = 0xf8;
|
||||
}
|
||||
}
|
||||
reg_write(RTL837X_REG_SMI_PORT_POLLING);
|
||||
// Enable MDC
|
||||
reg_read_m(RTL837X_REG_SMI_CTRL);
|
||||
sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2
|
||||
reg_write_m(RTL837X_REG_SMI_CTRL);
|
||||
delay(50);
|
||||
|
||||
if (!machine_detected.isRTL8373) {
|
||||
// Change I2C addresses for SMI of the non-existent PHYs
|
||||
// r6450:000020e6 R6450-000000e6
|
||||
reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
sfr_mask_data(1, 0x7c, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
|
||||
// r644c:0a418820 R644c-0a400820
|
||||
reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
sfr_mask_data(2, 0x0f, 0);
|
||||
sfr_mask_data(1, 0x80, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
}
|
||||
|
||||
if (machine.n_10g == 2) {
|
||||
// Set address of second external PHY on port 8
|
||||
REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setup_i2c(void) __banked
|
||||
{
|
||||
REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0);
|
||||
// Configure SFP EEPROM address (0x50) as I2C device address
|
||||
// Configure SFP readings address (0x51) as I2C device address
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff);
|
||||
|
||||
REG_SET(RTL837X_REG_I2C_CTRL2, 0);
|
||||
|
||||
// HW Control register, enable I2C depending on PIN configuration
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl);
|
||||
const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda);
|
||||
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
||||
switch (scl_bus) {
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 15-16 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x80, 0x80);
|
||||
sfr_mask_data(2, 0x01, 0x00);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 11-12 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x18, 0x08);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 7-8 0b01 -> SCL
|
||||
sfr_mask_data(0, 0x80, 0x80);
|
||||
sfr_mask_data(1, 0x01, 0x00);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n');
|
||||
}
|
||||
|
||||
switch (sda_bus) {
|
||||
case 4:
|
||||
// Bit 29 0b0 -> SDA
|
||||
sfr_mask_data(3, 0x20, 0x00);
|
||||
break;
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 17-18 0b01 -> SDA
|
||||
sfr_mask_data(2, 0x06, 0x02);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 13-14 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x60, 0x20);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 9-10 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x06, 0x02);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n');
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
}
|
||||
|
||||
|
||||
/* Give the switch a name carrying the tail of its MAC, so several of them on
|
||||
* one network are distinguishable out of the box. Called after the startup
|
||||
* config has been replayed and returns at once if that config already set a
|
||||
* name, so a configured switch does no work for it (suggested in review).
|
||||
*
|
||||
* Written without a loop on purpose. Locals - counters and pointers alike -
|
||||
* land in the 8051's internal-RAM overlay, and on an image with LACP and STP
|
||||
* both enabled that overlay is exhausted: a loop here makes the linker fail
|
||||
* with "Could not get 8 consecutive bytes in internal RAM for area OSEG".
|
||||
* Moving the code into its own function does not help; the overlay is shared
|
||||
* across the whole image. Hoisting the locals to xdata does not help either,
|
||||
* because itohex() is inline and brings its own frame. */
|
||||
void set_hostname_default(void) __banked
|
||||
{
|
||||
if (hostname[0] != NUL)
|
||||
return;
|
||||
|
||||
strcpy((__xdata uint8_t *)hostname, "RTLPlayground-");
|
||||
hostname[14] = hex[uip_ethaddr.addr[3] >> 4];
|
||||
hostname[15] = hex[uip_ethaddr.addr[3] & 0xf];
|
||||
hostname[16] = hex[uip_ethaddr.addr[4] >> 4];
|
||||
hostname[17] = hex[uip_ethaddr.addr[4] & 0xf];
|
||||
hostname[18] = hex[uip_ethaddr.addr[5] >> 4];
|
||||
hostname[19] = hex[uip_ethaddr.addr[5] & 0xf];
|
||||
hostname[20] = NUL;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef BOOT_H
|
||||
#define BOOT_H
|
||||
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode) __banked;
|
||||
void sds_config(uint8_t sds, uint8_t mode) __banked;
|
||||
void early_boot_handle_button(void) __banked;
|
||||
void rtl8224_enable(void) __banked;
|
||||
void nic_setup(void) __banked;
|
||||
void rtl8373_revision(void) __banked;
|
||||
void init_smi(void) __banked;
|
||||
void setup_i2c(void) __banked;
|
||||
void set_hostname_default(void) __banked;
|
||||
|
||||
#endif
|
||||
+108
-5
@@ -14,6 +14,7 @@
|
||||
#include "rtl837x_stp.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "rtl837x_bandwidth.h"
|
||||
#include "sfp.h"
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
#include "uip/uip.h"
|
||||
@@ -49,9 +50,6 @@ __xdata char port_names[9][PORT_NAME_SIZE];
|
||||
|
||||
extern __xdata uint16_t management_vlan;
|
||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||
extern __xdata uint8_t sfp_speed[2];
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t gpio_last_value[8] = { 0 };
|
||||
|
||||
// Temporatly for str to hex convertion value.
|
||||
@@ -66,6 +64,7 @@ __xdata uint8_t cmd_available;
|
||||
__xdata char save_cmd;
|
||||
|
||||
__xdata uint8_t ip[4];
|
||||
__xdata uint8_t mac_parse_result[6];
|
||||
|
||||
/* Scratch for parse_syslog(), in xdata: a local here would take internal RAM
|
||||
* the linker has none of. */
|
||||
@@ -106,7 +105,6 @@ inline uint8_t isnumber(uint8_t l)
|
||||
return (l <= ('9'-'0'));
|
||||
}
|
||||
|
||||
|
||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd)
|
||||
{
|
||||
if (cmd_words_len == 0 || start > (cmd_words_len - 1)) {
|
||||
@@ -349,7 +347,7 @@ err:
|
||||
}
|
||||
|
||||
// Prints an IPv4 address.
|
||||
void print_ip(__xdata uint8_t * ptr)
|
||||
void print_ip(__xdata uint8_t * ptr) __banked
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint8_t num;
|
||||
@@ -364,6 +362,109 @@ void print_ip(__xdata uint8_t * ptr)
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a MAC address.
|
||||
void print_mac(__xdata uint8_t *ptr) __banked
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint8_t num;
|
||||
|
||||
while (1) {
|
||||
num = *ptr++;
|
||||
print_byte(num);
|
||||
if (++idx == 6)
|
||||
break;
|
||||
|
||||
write_char(':');
|
||||
}
|
||||
}
|
||||
|
||||
// Parses a MAC address "aa:bb:cc:dd:ee:ff" (":" or "-" separators) from
|
||||
// cmd_buffer starting at idx into the global mac_parse_result[6]. Each octet
|
||||
// must be exactly two hex digits with a separator between octets and nothing
|
||||
// trailing, so repeated separators, missing digits or a trailing hex digit are
|
||||
// rejected. Returns the number of bytes consumed, or 0 on error.
|
||||
uint8_t parse_mac(uint8_t idx)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
uint8_t c = ':';
|
||||
|
||||
do {
|
||||
if (c != ':' && c != '-')
|
||||
goto err;
|
||||
|
||||
__bit again = true;
|
||||
uint8_t v = 0;
|
||||
|
||||
while(1) {
|
||||
c = cmd_buffer[idx++];
|
||||
c -= '0';
|
||||
if (c > 9) {
|
||||
c |= 0x20;
|
||||
c += '0' - 'a';
|
||||
if (c > 5)
|
||||
goto err;
|
||||
c += 10;
|
||||
}
|
||||
// force swap-instr.
|
||||
v = (v << 4) | (v >> 4);
|
||||
v |= c;
|
||||
|
||||
if (again)
|
||||
again = false;
|
||||
else
|
||||
break;
|
||||
}
|
||||
mac_parse_result[b++] = v;
|
||||
|
||||
c = cmd_buffer[idx++];
|
||||
} while(b < 6);
|
||||
|
||||
if (c == ' ' || c == NUL)
|
||||
return idx;
|
||||
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
|
||||
// the current one with a bare "mac"). Refuses blank/multicast/locally
|
||||
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
|
||||
// re-registers the static L2 management entry so the change applies without a
|
||||
// reboot. As a regular command a "mac ..." line in the startup config applies
|
||||
// on every boot (execute_config runs before the final static L2 entry).
|
||||
void parse_mac_cmd(void)
|
||||
{
|
||||
if (cmd_words_len == 1) {
|
||||
print_string("Current MAC: ");
|
||||
print_mac(uip_ethaddr.addr);
|
||||
write_char('\n');
|
||||
return;
|
||||
}
|
||||
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1])) {
|
||||
print_string("Error: mac [<aa:bb:cc:dd:ee:ff>]\n");
|
||||
return;
|
||||
}
|
||||
if ((mac_parse_result[0] & 0x03) || ((mac_parse_result[0] | mac_parse_result[1] | mac_parse_result[2]) == 0)) {
|
||||
print_string("refusing: must be unicast, globally administered\n");
|
||||
return;
|
||||
}
|
||||
if (memcmp(mac_parse_result, uip_ethaddr.addr, 6) == 0) {
|
||||
print_string("MAC unchanged\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap the static management entry over to the new address: remove the
|
||||
// old one (still in uip_ethaddr) before overwriting it.
|
||||
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, true);
|
||||
memcpy(uip_ethaddr.addr, mac_parse_result, 6);
|
||||
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, false);
|
||||
|
||||
print_string("MAC set to: ");
|
||||
print_mac(uip_ethaddr.addr);
|
||||
write_char('\n');
|
||||
print_string("Save the startup config to keep it across reboots\n");
|
||||
}
|
||||
|
||||
|
||||
void parse_lag(void)
|
||||
{
|
||||
@@ -1704,6 +1805,8 @@ void cmd_parser(void) __banked
|
||||
igmp_show();
|
||||
else
|
||||
print_string("Error: igmp on|off|show\n");
|
||||
} else if (cmd_compare(0, "mac")) {
|
||||
parse_mac_cmd();
|
||||
} else if (cmd_compare(0, "hostname")) {
|
||||
/* "hostname" alone reports the current name; "hostname <text>"
|
||||
* sets it, sanitized to JSON-safe printable ASCII. A name with
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ void cmd_tokenize(void) __banked;
|
||||
void cmd_parser(void) __banked;
|
||||
void execute_config(void) __banked;
|
||||
void execute_commands(__xdata uint8_t *p) __banked;
|
||||
void print_ip(__xdata uint8_t *ptr);
|
||||
void print_ip(__xdata uint8_t *ptr) __banked;
|
||||
void print_mac(__xdata uint8_t *ptr) __banked;
|
||||
void print_sw_version(void) __banked;
|
||||
void clear_command_history(void) __banked;
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# MokerLink POE-2G080110GS
|
||||
|
||||
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
|
||||
|
||||
## Brands
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
||||
|
||||
## Hardware overview
|
||||
Front
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-front.jpg" width="300" />
|
||||
|
||||
Label
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-label.jpg" width="300" />
|
||||
|
||||
The stock firmware from a POE-2G080110GS device had a sha256sum of `4c280853465eaad80e1772075c0f2d29c11fb8c561547f06353d3a5443c388e9`.
|
||||
|
||||
### PCB
|
||||
|
||||
Top silkscreen is marked `2M-PCB51-ML-V1.1`. PoE is provided by RTL8238C. Flash chip is 4 MB Winbond 25Q32JV (U8).
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-pcb.jpg" width="300" />
|
||||
|
||||
> [!CAUTION]
|
||||
> This device operates on mains voltage, which can be a dangerous or potentially lethal hazard. Even after the device is unplugged, high-voltage capacitors can remain charged afterward and may still shock you. Do not attempt to open/disassemble a mains powered device unless you understand how to do so safely. Also, opening the device may void your warranty.
|
||||
|
||||
## Notes
|
||||
|
||||
The stock firmware blinks both the 2.5G and 1G LEDs on activity, despite the front of the device indicating that each LED should be independent. The `POE_2G080110GS` machine config behaves as the front of the device indicates (and what seems more logical) -- each port LED turns on and blinks independently.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 934 KiB |
+26
@@ -58,6 +58,32 @@ port set to admit tagged frames only (`ingress <port>t`) never delivers one
|
||||
to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that
|
||||
state.
|
||||
|
||||
## Link aggregation
|
||||
|
||||
A LAG (Link Aggregation Group) is handled like an additional port by the STP
|
||||
protocol, with its own timers and states. The switch devices support up to 4
|
||||
LAGs, which are shown alongside the physical ports in the STP status. A group
|
||||
carries its own path cost, priority, edge and guard settings, and gets its own
|
||||
row on the Spanning Tree page.
|
||||
|
||||
```
|
||||
stp lag 1 cost 10000 # the group decides, not its members
|
||||
stp lag 1 edge off
|
||||
```
|
||||
|
||||
LAGs are configured via the `lag` command. Once a port is a member of a LAG it
|
||||
can no longer be configured individually for STP, so `stp port <n>` on a member
|
||||
tells you which group to configure instead. Membership is re-read from the
|
||||
aggregation registers once a second, so a group changing under LACP is picked
|
||||
up without any coordination between the two.
|
||||
|
||||
The switch hardware does not handle STP state for a LAG as a whole. State
|
||||
changes for the members have to be done by the firmware, updating every member
|
||||
port, which is possible using a single register write. BPDUs go out through the
|
||||
lowest member and carry the group's own port id. Losing one member of a live
|
||||
LAG is not a topology change; the logical port only goes down with its last
|
||||
link.
|
||||
|
||||
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
|
||||
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
|
||||
blocking forwards nothing between ports, but it still sends what the CPU
|
||||
|
||||
@@ -23,6 +23,7 @@ The following devices have been tested and are fully working:
|
||||
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
||||
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
||||
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
|
||||
+54
-31
@@ -1020,6 +1020,13 @@ const conf_cmds = [
|
||||
/^stp\s+port\s+\d{1,2}\s+guard\s+(none|bpdu|root)$/,
|
||||
/^stp\s+port\s+\d{1,2}\s+filter\s+(on|off)$/,
|
||||
/^stp\s+port\s+\d{1,2}\s+p2p\s+(auto|on|off)$/,
|
||||
/^stp\s+lag\s+[1-4]\s+(on|off)$/,
|
||||
/^stp\s+lag\s+[1-4]\s+edge\s+(on|off|auto)$/,
|
||||
/^stp\s+lag\s+[1-4]\s+cost\s+\d{1,9}$/,
|
||||
/^stp\s+lag\s+[1-4]\s+prio\s+\d{1,3}$/,
|
||||
/^stp\s+lag\s+[1-4]\s+guard\s+(none|bpdu|root)$/,
|
||||
/^stp\s+lag\s+[1-4]\s+filter\s+(on|off)$/,
|
||||
/^stp\s+lag\s+[1-4]\s+p2p\s+(auto|on|off)$/,
|
||||
/^igmp\s+(on|off)$/,
|
||||
/^mtu\s+\d{1,2}\s+\d+$/,
|
||||
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
|
||||
@@ -1055,6 +1062,7 @@ const conf_overwrite = [
|
||||
/^isolate\s+\d{1,2}\b/,
|
||||
/^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/,
|
||||
/^stp\s+port\s+\d{1,2}\s+(edge|cost|prio|guard|filter|p2p)\b/,
|
||||
/^stp\s+lag\s+[1-4]\s+(edge|cost|prio|guard|filter|p2p)\b/,
|
||||
/^igmp\b/,
|
||||
/^mtu\s+\d{1,2}\b/,
|
||||
/^bw\s+(in|out)\s+\d{1,2}\b/,
|
||||
@@ -2601,45 +2609,58 @@ function num(id, min, max, onch) {
|
||||
return n;
|
||||
}
|
||||
|
||||
function members(mask) {
|
||||
const a = [];
|
||||
for (let i = 0; i < numPorts; i++)
|
||||
if (mask & (1 << i)) a.push(logToPhysPort[i]);
|
||||
return a.join(",");
|
||||
}
|
||||
|
||||
function buildPortsTable(ports) {
|
||||
const tbl = document.getElementById("stpPortsTbl");
|
||||
const stat = document.getElementById("stpStatTbl");
|
||||
for (const p of [...ports].sort((a, b) => a.p - b.p)) {
|
||||
p.n = p.lag ? "lag " + p.lag : "port " + p.p;
|
||||
p.k = p.lag ? "L" + p.lag : p.p;
|
||||
const tr = tbl.insertRow();
|
||||
tr.insertCell().textContent = p.p;
|
||||
tr.insertCell().appendChild(sel("en_" + p.p,
|
||||
tr.insertCell().textContent = p.lag
|
||||
? "LAG" + p.lag + " (" + members(p.mbr) + ")"
|
||||
: p.p;
|
||||
tr.insertCell().appendChild(sel("en_" + p.k,
|
||||
[["on","Enable"],["off","Disable"]],
|
||||
e => stpCmd("stp port " + p.p + " " + e.target.value)));
|
||||
const pc = num("cost_" + p.p, 0, 200000000,
|
||||
e => stpCmd("stp port " + p.p + " cost " + e.target.value));
|
||||
e => stpCmd("stp " + p.n + " " + e.target.value)));
|
||||
const pc = num("cost_" + p.k, 0, 200000000,
|
||||
e => stpCmd("stp " + p.n + " cost " + e.target.value));
|
||||
pc.style.width = "7em";
|
||||
pc.title = "0 - 200000000 (0 = Auto)";
|
||||
tr.insertCell().appendChild(pc);
|
||||
const pr = sel("prio_" + p.p, [],
|
||||
e => stpCmd("stp port " + p.p + " prio " + e.target.value));
|
||||
const pr = sel("prio_" + p.k, [],
|
||||
e => stpCmd("stp " + p.n + " prio " + e.target.value));
|
||||
for (let v = 0; v <= 240; v += 16) {
|
||||
const o = document.createElement("option");
|
||||
o.value = v; o.textContent = v + (v === 128 ? " (default)" : "");
|
||||
pr.appendChild(o);
|
||||
}
|
||||
tr.insertCell().appendChild(pr);
|
||||
tr.insertCell().appendChild(sel("edge_" + p.p,
|
||||
tr.insertCell().appendChild(sel("edge_" + p.k,
|
||||
[["auto","Auto"],["on","Enable"],["off","Disable"]],
|
||||
e => stpCmd("stp port " + p.p + " edge " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("filt_" + p.p,
|
||||
e => stpCmd("stp " + p.n + " edge " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("filt_" + p.k,
|
||||
[["off","Disable"],["on","Enable"]],
|
||||
e => stpCmd("stp port " + p.p + " filter " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("guard_" + p.p,
|
||||
e => stpCmd("stp " + p.n + " filter " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("guard_" + p.k,
|
||||
[["none","None"],["bpdu","BPDU"],["root","Root"]],
|
||||
e => stpCmd("stp port " + p.p + " guard " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("p2p_" + p.p,
|
||||
e => stpCmd("stp " + p.n + " guard " + e.target.value)));
|
||||
tr.insertCell().appendChild(sel("p2p_" + p.k,
|
||||
[["auto","Auto"],["on","Enable"],["off","Disable"]],
|
||||
e => stpCmd("stp port " + p.p + " p2p " + e.target.value)));
|
||||
e => stpCmd("stp " + p.n + " p2p " + e.target.value)));
|
||||
|
||||
const sr = stat.insertRow();
|
||||
sr.insertCell().textContent = p.p;
|
||||
sr.insertCell().textContent = p.lag
|
||||
? "LAG" + p.lag + " (" + members(p.mbr) + ")"
|
||||
: p.p;
|
||||
for (const id of ["st","role","db","dp","dc","oe","op"])
|
||||
sr.insertCell().id = id + "_" + p.p;
|
||||
sr.insertCell().id = id + "_" + p.k;
|
||||
}
|
||||
stpRows = ports.length;
|
||||
}
|
||||
@@ -2672,18 +2693,19 @@ function fetchStp() {
|
||||
+ " \u2014 topology changes: " + parseInt(s.tc, 16))
|
||||
: "";
|
||||
for (const p of s.ports) {
|
||||
const k = p.lag ? "L" + p.lag : p.p;
|
||||
const trip = (p.f & PF_TRIPPED) ? " (guard!)" : "";
|
||||
document.getElementById("st_" + p.p).textContent =
|
||||
document.getElementById("st_" + k).textContent =
|
||||
s.on ? STP_STATES[p.st] + trip : "-";
|
||||
document.getElementById("role_" + p.p).textContent =
|
||||
document.getElementById("role_" + k).textContent =
|
||||
s.on ? STP_ROLES[p.role] : "-";
|
||||
document.getElementById("db_" + p.p).textContent = s.on ? fmtBridgeId(p.db) : "-";
|
||||
document.getElementById("dp_" + p.p).textContent =
|
||||
document.getElementById("db_" + k).textContent = s.on ? fmtBridgeId(p.db) : "-";
|
||||
document.getElementById("dp_" + k).textContent =
|
||||
s.on ? (parseInt(p.dp.slice(0, 2), 16) + "-" + parseInt(p.dp.slice(2), 16)) : "-";
|
||||
document.getElementById("dc_" + p.p).textContent = s.on ? parseInt(p.dc, 16) : "-";
|
||||
document.getElementById("oe_" + p.p).textContent =
|
||||
document.getElementById("dc_" + k).textContent = s.on ? parseInt(p.dc, 16) : "-";
|
||||
document.getElementById("oe_" + k).textContent =
|
||||
s.on ? ((p.f & PF_OPEREDGE) ? "True" : "False") : "-";
|
||||
document.getElementById("op_" + p.p).textContent = s.on ? (p.p2 == 2 ? "False" : "True") : "-";
|
||||
document.getElementById("op_" + k).textContent = s.on ? (p.p2 == 2 ? "False" : "True") : "-";
|
||||
}
|
||||
if (stpDirty)
|
||||
return;
|
||||
@@ -2695,15 +2717,16 @@ function fetchStp() {
|
||||
document.getElementById("bFwd").value = s.fwd;
|
||||
document.getElementById("bTxhold").value = s.txhold;
|
||||
for (const p of s.ports) {
|
||||
document.getElementById("en_" + p.p).value = (p.f & PF_ENABLED) ? "on" : "off";
|
||||
document.getElementById("edge_" + p.p).value =
|
||||
const k = p.lag ? "L" + p.lag : p.p;
|
||||
document.getElementById("en_" + k).value = (p.f & PF_ENABLED) ? "on" : "off";
|
||||
document.getElementById("edge_" + k).value =
|
||||
(p.f & PF_ADMEDGE) ? "on" : ((p.f & PF_AUTOEDGE) ? "auto" : "off");
|
||||
document.getElementById("cost_" + p.p).value = parseInt(p.pc, 16);
|
||||
document.getElementById("prio_" + p.p).value = p.prio;
|
||||
document.getElementById("p2p_" + p.p).value = ["auto","on","off"][p.p2];
|
||||
document.getElementById("guard_" + p.p).value =
|
||||
document.getElementById("cost_" + k).value = parseInt(p.pc, 16);
|
||||
document.getElementById("prio_" + k).value = p.prio;
|
||||
document.getElementById("p2p_" + k).value = ["auto","on","off"][p.p2];
|
||||
document.getElementById("guard_" + k).value =
|
||||
(p.f & PF_BPDUGUARD) ? "bpdu" : ((p.f & PF_ROOTGUARD) ? "root" : "none");
|
||||
document.getElementById("filt_" + p.p).value = (p.f & PF_FILTER) ? "on" : "off";
|
||||
document.getElementById("filt_" + k).value = (p.f & PF_FILTER) ? "on" : "off";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+32
-4
@@ -607,17 +607,43 @@ void send_stp(void)
|
||||
slen += strtox(outbuf + slen, "\",\"weRoot\":");
|
||||
bool_to_html(stp_root_port == 0xff ? 1 : 0);
|
||||
slen += strtox(outbuf + slen, ",\"rootPort\":");
|
||||
itoa_html(stp_root_port == 0xff ? 0 : machine.log_to_phys_port[stp_root_port]);
|
||||
j = stp_root_port;
|
||||
if (j != 0xff && j >= STP_LAG_BASE) {
|
||||
j = 0;
|
||||
while (j < STP_LAG_BASE && !((stp_lag_mask[stp_root_port - STP_LAG_BASE] >> j) & 1))
|
||||
j++;
|
||||
if (j >= STP_LAG_BASE)
|
||||
j = 0;
|
||||
}
|
||||
itoa_html(j == 0xff ? 0 : machine.log_to_phys_port[j]);
|
||||
slen += strtox(outbuf + slen, ",\"tc\":\"");
|
||||
byte_to_html(stp_tc_count >> 8);
|
||||
byte_to_html(stp_tc_count);
|
||||
slen += strtox(outbuf + slen, "\",\"ports\":[");
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
for (i = 0; i < STP_ENTITIES; i++) {
|
||||
if (i < STP_LAG_BASE && (i < machine.min_port || i > machine.max_port))
|
||||
continue;
|
||||
if (i < STP_LAG_BASE && stp_ent_of[i] != i)
|
||||
continue;
|
||||
if (i >= STP_LAG_BASE && !stp_lag_mask[i - STP_LAG_BASE])
|
||||
continue;
|
||||
slen += strtox(outbuf + slen, "{\"p\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
itoa_html(i < STP_LAG_BASE ? machine.log_to_phys_port[i] : 0);
|
||||
slen += strtox(outbuf + slen, ",\"lag\":");
|
||||
itoa_html(i < STP_LAG_BASE ? 0 : i - STP_LAG_BASE + 1);
|
||||
slen += strtox(outbuf + slen, ",\"mbr\":");
|
||||
itoa16_html(i < STP_LAG_BASE ? 0 : stp_lag_mask[i - STP_LAG_BASE]);
|
||||
slen += strtox(outbuf + slen, ",\"st\":");
|
||||
st = (sfr_data[3 - (i >> 2)] >> ((i << 1) & 0x7)) & 0x3;
|
||||
j = i;
|
||||
if (i >= STP_LAG_BASE) {
|
||||
j = 0;
|
||||
while (j < STP_LAG_BASE && !((stp_lag_mask[i - STP_LAG_BASE] >> j) & 1))
|
||||
j++;
|
||||
if (j >= STP_LAG_BASE)
|
||||
j = 0;
|
||||
}
|
||||
st = (sfr_data[3 - (j >> 2)] >> ((j << 1) & 0x7)) & 0x3;
|
||||
itoa_html(st);
|
||||
slen += strtox(outbuf + slen, ",\"role\":");
|
||||
if (!(stp_pflags[i] & STP_PF_ENABLED) || (stp_pflags[i] & STP_PF_TRIPPED))
|
||||
@@ -658,6 +684,8 @@ void send_stp(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void send_eee(void)
|
||||
{
|
||||
dbg_string("send_eee called\nsending EEE status\n");
|
||||
|
||||
@@ -247,6 +247,7 @@ __code const struct machine machine = {
|
||||
.led_mux = {0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x09, 0x0d, 0x10,
|
||||
0x11, 0x0e, 0x14, 0x11, 0x12, 0x15, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21},
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
};
|
||||
|
||||
#elif defined MACHINE_SWGT024_V2_0_MANAGED
|
||||
@@ -1144,6 +1145,50 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_POE_2G080110GS
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "MokerLink POE-2G080110GS",
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.led_sets = {
|
||||
{
|
||||
/* SET0: RJ45 2.5G = amber, 1G/100M/10M = green */
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT, /* amber */
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* green */
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
/* SET1: SFP+ port = green */
|
||||
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M |
|
||||
LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08,
|
||||
0x09, 0x0c, 0x09, 0x0d, 0x10,
|
||||
0x11, 0x0e, 0x14, 0x11, 0x12,
|
||||
0x15, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c,
|
||||
0x1d, 0x20, 0x21 },
|
||||
};
|
||||
|
||||
#else
|
||||
#error "Please select a machine type in machine.h"
|
||||
#endif
|
||||
@@ -44,6 +44,7 @@
|
||||
// #define MACHINE_SWTG024AS_V2_0
|
||||
// #define MACHINE_FG_4GT_2SX_V2_0
|
||||
// #define MACHINE_FG_8GT_1SX
|
||||
// #define MACHINE_POE_2G080110GS
|
||||
|
||||
typedef struct {
|
||||
// GPIO pins for SDA/SCL
|
||||
|
||||
+2
-4
@@ -173,6 +173,7 @@ void reset_chip(void);
|
||||
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
|
||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
|
||||
void memset(__xdata uint8_t *dst, __xdata uint8_t v, uint8_t len);
|
||||
int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len);
|
||||
uint16_t strlen(__code const char *s);
|
||||
uint16_t strlen_x(__xdata const char *s);
|
||||
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
||||
@@ -184,12 +185,9 @@ void tcpip_output(void);
|
||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||
void get_random_32(void);
|
||||
void read_reg_timer(__xdata uint32_t * tmr);
|
||||
bool sfp_print_info(uint8_t sfp);
|
||||
bool gpio_pin_test(uint8_t pin);
|
||||
void set_sys_led_state(uint8_t state);
|
||||
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
||||
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode);
|
||||
void sds_config(uint8_t sds, uint8_t mode);
|
||||
void handle_sfp(void);
|
||||
void flash_default_config(void);
|
||||
#endif
|
||||
+2
-2
@@ -295,7 +295,7 @@ void igmp_packet_handler(void) __banked
|
||||
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
|
||||
}
|
||||
// Update (found) entry with portmask from trapped Packet
|
||||
entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
entry.pmask |= ((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else if (IGMP_I->igmp_rtype == 0x3){ // Leave group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
@@ -312,7 +312,7 @@ void igmp_packet_handler(void) __banked
|
||||
write_char('\n');
|
||||
#endif
|
||||
// Remove portmask of IGMP packet from entry
|
||||
entry.pmask &= ~(1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
entry.pmask &= ~(((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f)); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else {
|
||||
print_string("IGMP Entry already deleted\n");
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "rtl837x_phy.h"
|
||||
#include "phy.h"
|
||||
#include "machine.h"
|
||||
#include "boot.h"
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __code struct machine machine;
|
||||
|
||||
+276
-68
@@ -47,31 +47,36 @@ __xdata uint8_t stp_rstp; /* 1 = RST BPDUs, 0 = legacy Config BPDUs */
|
||||
__xdata uint8_t stp_txhold; /* BPDUs per port per second */
|
||||
|
||||
|
||||
__xdata uint8_t stp_pflags[10];
|
||||
__xdata uint32_t stp_pcost[10]; /* 0 = auto */
|
||||
__xdata uint8_t stp_pprio[10];
|
||||
__xdata uint8_t stp_pp2p[10]; /* admin point-to-point: 0 auto, 1 on, 2 off */
|
||||
__xdata uint8_t stp_ent_of[STP_PORTS];
|
||||
__xdata uint16_t stp_lag_mask[STP_LAG_COUNT];
|
||||
__xdata uint8_t stp_ss_i;
|
||||
__xdata uint8_t stp_map_dirty;
|
||||
__xdata uint8_t stp_pflags[STP_ENTITIES];
|
||||
__xdata uint32_t stp_pcost[STP_ENTITIES]; /* 0 = auto */
|
||||
__xdata uint8_t stp_pprio[STP_ENTITIES];
|
||||
__xdata uint8_t stp_pp2p[STP_ENTITIES]; /* admin point-to-point: 0 auto, 1 on, 2 off */
|
||||
|
||||
/* Designated bridge, port and cost last heard on the port; stp_bpdu_age tells
|
||||
* whether they are still current.
|
||||
*/
|
||||
__xdata struct bridge stp_dbridge[10];
|
||||
__xdata uint16_t stp_dpid[10];
|
||||
__xdata uint32_t stp_dcost[10];
|
||||
__xdata struct bridge stp_dbridge[STP_ENTITIES];
|
||||
__xdata uint16_t stp_dpid[STP_ENTITIES];
|
||||
__xdata uint32_t stp_dcost[STP_ENTITIES];
|
||||
|
||||
/* ---- Status / runtime ---- */
|
||||
__xdata struct bridge root_bridge;
|
||||
__xdata uint32_t root_bridge_cost; /* our cost to the root (rx cost + root port cost) */
|
||||
__xdata uint8_t stp_root_port; /* 0xff = we are the root */
|
||||
__xdata uint16_t stp_tc_count;
|
||||
__xdata uint16_t stp_scratch16; /* scratch for status printing only */
|
||||
__xdata uint16_t stp_scratch16; /* scratch for status printing and the lag map */
|
||||
__xdata uint8_t stp_st_of;
|
||||
|
||||
__xdata uint16_t port_timers[10]; /* listen-period countdown (0 = not listening) */
|
||||
__xdata uint16_t port_hello[10]; /* hello TX countdown */
|
||||
__xdata uint16_t stp_bpdu_age[10]; /* ticks since last BPDU seen on port (saturating) */
|
||||
__xdata uint8_t stp_loop_held[10]; /* port is out of forwarding because a loop was seen on it */
|
||||
__xdata uint8_t stp_tx_budget[10]; /* tx hold: BPDUs left in the current second */
|
||||
__xdata uint8_t stp_tx_count[10]; /* BPDUs actually put on the wire, wraps at 256 */
|
||||
__xdata uint16_t port_timers[STP_ENTITIES]; /* listen-period countdown (0 = not listening) */
|
||||
__xdata uint16_t port_hello[STP_ENTITIES]; /* hello TX countdown */
|
||||
__xdata uint16_t stp_bpdu_age[STP_ENTITIES]; /* ticks since last BPDU seen on port (saturating) */
|
||||
__xdata uint8_t stp_loop_held[STP_ENTITIES]; /* port is out of forwarding because a loop was seen on it */
|
||||
__xdata uint8_t stp_tx_budget[STP_ENTITIES]; /* tx hold: BPDUs left in the current second */
|
||||
__xdata uint8_t stp_tx_count[STP_ENTITIES]; /* BPDUs actually put on the wire, wraps at 256 */
|
||||
__xdata uint16_t stp_sec_tick; /* 1 s window for the tx budget */
|
||||
__xdata uint16_t stp_link_prev; /* carrier bitmap as of the last check */
|
||||
__xdata uint16_t stp_link_now;
|
||||
@@ -161,10 +166,22 @@ struct stp_pkt_in {
|
||||
#define BPDU_ROLE_ROOT (0b10 << 2)
|
||||
#define BPDU_ROLE_DESIGNATED (0b11 << 2)
|
||||
|
||||
/* Port state as the MSTP register encodes it, two bits per port. */
|
||||
#define STP_ST_DISABLED 0b00
|
||||
#define STP_ST_BLOCKING 0b01
|
||||
#define STP_ST_LEARNING 0b10
|
||||
#define STP_ST_FORWARDING 0b11
|
||||
#define STP_ST_MASK 0b11
|
||||
|
||||
/* Console messages name the port on the front panel, not the internal index. */
|
||||
static void print_port_nl(uint8_t port) __reentrant
|
||||
{
|
||||
if (port >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + port - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[port]);
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
@@ -184,6 +201,8 @@ static __code const char stp_state_txt[] = "off blocklearnfwd ";
|
||||
static __code const char stp_role_txt[] = "desgroot";
|
||||
static __code const char stp_edge_txt[] = "no yes ";
|
||||
|
||||
static uint8_t stp_ent_active(uint8_t e) __reentrant;
|
||||
|
||||
static void print_field(__code const char *txt, uint8_t idx, uint8_t width) __reentrant
|
||||
{
|
||||
txt += idx * width;
|
||||
@@ -207,7 +226,12 @@ static void stp_status(void)
|
||||
print_string(" (this switch)\n");
|
||||
} else {
|
||||
print_string(" port ");
|
||||
if (stp_root_port >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + stp_root_port - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[stp_root_port]);
|
||||
}
|
||||
print_string(" cost ");
|
||||
print_long(root_bridge_cost);
|
||||
write_char('\n');
|
||||
@@ -217,11 +241,26 @@ static void stp_status(void)
|
||||
write_char('\n');
|
||||
print_string("port state role edge tx bpdu\n");
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (!stp_ent_active(stp_i))
|
||||
continue;
|
||||
write_char(' ');
|
||||
if (stp_i >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + stp_i - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[stp_i]);
|
||||
}
|
||||
print_string(" ");
|
||||
print_field(stp_state_txt, (sfr_data[3 - (stp_i >> 2)] >> ((stp_i << 1) & 0x7)) & 0x3, 5);
|
||||
stp_st_of = stp_i;
|
||||
if (stp_i >= STP_LAG_BASE) {
|
||||
stp_st_of = 0;
|
||||
while (stp_st_of < STP_PORTS && !((stp_lag_mask[stp_i - STP_LAG_BASE] >> stp_st_of) & 1))
|
||||
stp_st_of++;
|
||||
if (stp_st_of >= STP_PORTS)
|
||||
stp_st_of = 0;
|
||||
}
|
||||
print_field(stp_state_txt, (sfr_data[3 - (stp_st_of >> 2)] >> ((stp_st_of << 1) & 0x7)) & 0x3, 5);
|
||||
write_char(' ');
|
||||
print_field(stp_role_txt, stp_i == stp_root_port ? 1 : 0, 4);
|
||||
write_char(' ');
|
||||
@@ -266,18 +305,95 @@ int8_t cmpBytes(__xdata uint8_t *m1, __xdata uint8_t *m2, uint8_t n) __reentrant
|
||||
}
|
||||
|
||||
|
||||
/* Write one port's 2-bit state into the ASIC's MSTP register.
|
||||
* 00 disable, 01 blocking, 10 learning, 11 forwarding. */
|
||||
static void stp_lag_map(void)
|
||||
{
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
stp_ent_of[stp_ss_i] = stp_ss_i;
|
||||
for (stp_scratch = 0; stp_scratch < STP_LAG_COUNT; stp_scratch++) {
|
||||
stp_scratch16 = port_lag_members_get(stp_scratch);
|
||||
if (stp_lag_mask[stp_scratch] != stp_scratch16)
|
||||
stp_map_dirty = 1;
|
||||
stp_lag_mask[stp_scratch] = stp_scratch16;
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if ((stp_lag_mask[stp_scratch] >> stp_ss_i) & 1)
|
||||
stp_ent_of[stp_ss_i] = STP_LAG_BASE + stp_scratch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_ent_active(uint8_t e) __reentrant
|
||||
{
|
||||
if (e >= STP_ENTITIES)
|
||||
return 0;
|
||||
if (e >= STP_LAG_BASE)
|
||||
return stp_lag_mask[e - STP_LAG_BASE] != 0;
|
||||
return e >= machine.min_port && e <= machine.max_port && stp_ent_of[e] == e;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_ent_has(uint8_t ent, uint8_t p) __reentrant
|
||||
{
|
||||
if (ent < STP_LAG_BASE)
|
||||
return ent == p;
|
||||
return (stp_lag_mask[ent - STP_LAG_BASE] >> p) & 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_state_port(uint8_t e) __reentrant
|
||||
{
|
||||
if (e < STP_LAG_BASE)
|
||||
return e;
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if ((stp_lag_mask[e - STP_LAG_BASE] >> stp_ss_i) & 1)
|
||||
return stp_ss_i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void stp_state_bits(uint8_t port, uint8_t state) __reentrant
|
||||
{
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if (stp_ent_has(port, stp_ss_i))
|
||||
sfr_data[3 - (stp_ss_i >> 2)] |= (uint8_t)(state << ((stp_ss_i << 1) & 0x7));
|
||||
}
|
||||
|
||||
|
||||
static void stp_state_set(uint8_t port, uint8_t state) __reentrant
|
||||
{
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
stp_scratch = 3 - (port >> 2);
|
||||
sfr_data[stp_scratch] &= ~(uint8_t)(0b11 << ((port << 1) & 0x7));
|
||||
sfr_data[stp_scratch] |= (uint8_t)(state << ((port << 1) & 0x7));
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++) {
|
||||
if (!stp_ent_has(port, stp_ss_i))
|
||||
continue;
|
||||
stp_scratch = 3 - (stp_ss_i >> 2);
|
||||
sfr_data[stp_scratch] &= ~(uint8_t)(STP_ST_MASK << ((stp_ss_i << 1) & 0x7));
|
||||
sfr_data[stp_scratch] |= (uint8_t)(state << ((stp_ss_i << 1) & 0x7));
|
||||
}
|
||||
reg_write_m(RTL837X_MSTP_STATES);
|
||||
}
|
||||
|
||||
|
||||
static void stp_ent_apply(uint8_t e) __reentrant
|
||||
{
|
||||
if (!(stp_pflags[e] & STP_PF_ENABLED)) {
|
||||
stp_state_set(e, STP_ST_FORWARDING);
|
||||
return;
|
||||
}
|
||||
if (stp_pflags[e] & STP_PF_TRIPPED) {
|
||||
stp_state_set(e, STP_ST_DISABLED);
|
||||
return;
|
||||
}
|
||||
if (stp_pflags[e] & STP_PF_ADMEDGE) {
|
||||
stp_pflags[e] |= STP_PF_OPEREDGE;
|
||||
stp_state_set(e, STP_ST_FORWARDING);
|
||||
return;
|
||||
}
|
||||
if (port_timers[e])
|
||||
stp_state_set(e, STP_ST_BLOCKING);
|
||||
else
|
||||
stp_state_set(e, ((stp_link_prev >> e) & 1) ? STP_ST_FORWARDING : STP_ST_BLOCKING);
|
||||
}
|
||||
|
||||
|
||||
/* Signal a topology change. Edge ports are exempt. */
|
||||
static void stp_topology_change(uint8_t port) __reentrant
|
||||
{
|
||||
@@ -285,8 +401,14 @@ static void stp_topology_change(uint8_t port) __reentrant
|
||||
return;
|
||||
stp_tc_count++;
|
||||
stp_tc_while = ((uint16_t)stp_maxage_s + stp_fwddelay_s) * STP_HZ;
|
||||
if (port >= STP_LAG_BASE) {
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++)
|
||||
if (stp_ent_has(port, i))
|
||||
port_l2_forget_port(i);
|
||||
} else {
|
||||
port_l2_forget_port(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Hold one port out of forwarding because a loop was seen on it, and keep
|
||||
@@ -296,7 +418,7 @@ static void stp_topology_change(uint8_t port) __reentrant
|
||||
*/
|
||||
static void stp_loop_hold_peer(uint8_t port) __reentrant
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port)
|
||||
if (port >= STP_ENTITIES || !stp_ent_active(port))
|
||||
return;
|
||||
if (!(stp_pflags[port] & STP_PF_ENABLED))
|
||||
return;
|
||||
@@ -305,7 +427,7 @@ static void stp_loop_hold_peer(uint8_t port) __reentrant
|
||||
if (!port_timers[port]) {
|
||||
print_string("STP: loop detected, blocking port ");
|
||||
print_port_nl(port);
|
||||
stp_state_set(port, 0b01);
|
||||
stp_state_set(port, STP_ST_BLOCKING);
|
||||
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
||||
stp_topology_change(port);
|
||||
}
|
||||
@@ -348,7 +470,18 @@ void stp_cnf_send(uint8_t port) __reentrant
|
||||
STP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
||||
STP_O->rtl_tag.reason = 0x00;
|
||||
STP_O->rtl_tag.flags = HTONS(RTL_TAG_LEARN_DIS);
|
||||
if (port >= STP_LAG_BASE) {
|
||||
stp_scratch = 0;
|
||||
while (stp_scratch < STP_PORTS && !stp_ent_has(port, stp_scratch))
|
||||
stp_scratch++;
|
||||
if (stp_scratch >= STP_PORTS) {
|
||||
stp_tx_flags_extra = 0;
|
||||
return;
|
||||
}
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << stp_scratch);
|
||||
} else {
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
||||
}
|
||||
|
||||
STP_O->dsap = 0x42;
|
||||
STP_O->ssap = 0x42;
|
||||
@@ -359,8 +492,9 @@ void stp_cnf_send(uint8_t port) __reentrant
|
||||
STP_O->version = BPDU_VER_RSTP;
|
||||
STP_O->bpdu_type = BPDU_TYPE_RST;
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
stp_scratch = stp_state_port(port);
|
||||
STP_O->flags = port == stp_root_port ? BPDU_ROLE_ROOT : BPDU_ROLE_DESIGNATED;
|
||||
if (((sfr_data[3 - (port >> 2)] >> ((port << 1) & 0x7)) & 0b11) == 0b11)
|
||||
if (((sfr_data[3 - (stp_scratch >> 2)] >> ((stp_scratch << 1) & 0x7)) & STP_ST_MASK) == STP_ST_FORWARDING)
|
||||
STP_O->flags |= BPDU_FLAG_LEARNING | BPDU_FLAG_FORWARDING;
|
||||
} else {
|
||||
STP_O->msg_len = HTONS(BPDU_LEN_CONFIG);
|
||||
@@ -424,7 +558,7 @@ void stp_in(void) __banked
|
||||
stp_scratch = ((uint8_t)HTONS(STP_I->rtl_tag.pmask)) & 0x0f;
|
||||
if (stp_scratch < machine.min_port || stp_scratch > machine.max_port)
|
||||
return;
|
||||
port = stp_scratch;
|
||||
port = stp_ent_of[stp_scratch];
|
||||
|
||||
// Make sure this is the type of (R)STP packet we are interested in:
|
||||
if (!(STP_I->dsap == 0x42 && STP_I->ssap == 0x42 && STP_I->ctrl == 0x03))
|
||||
@@ -445,7 +579,7 @@ void stp_in(void) __banked
|
||||
print_string("STP: BPDU guard tripped, disabling port ");
|
||||
print_port_nl(port);
|
||||
stp_pflags[port] |= STP_PF_TRIPPED;
|
||||
stp_state_set(port, 0b00);
|
||||
stp_state_set(port, STP_ST_DISABLED);
|
||||
stp_tc_count++;
|
||||
return;
|
||||
}
|
||||
@@ -516,8 +650,9 @@ void stp_in(void) __banked
|
||||
uint8_t i;
|
||||
stp_tc_count++;
|
||||
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||
if (i != port && (stp_pflags[i] & STP_PF_ENABLED)
|
||||
&& !(stp_pflags[i] & STP_PF_OPEREDGE))
|
||||
if (!stp_ent_has(port, i)
|
||||
&& (stp_pflags[stp_ent_of[i]] & STP_PF_ENABLED)
|
||||
&& !(stp_pflags[stp_ent_of[i]] & STP_PF_OPEREDGE))
|
||||
port_l2_forget_port(i);
|
||||
}
|
||||
if (stp_tc_while < ((uint16_t)stp_hello_s + 1) * STP_HZ)
|
||||
@@ -535,7 +670,7 @@ void stp_in(void) __banked
|
||||
if (stp_pflags[port] & STP_PF_ROOTGUARD) {
|
||||
print_string("STP: root guard blocking port ");
|
||||
print_port_nl(port);
|
||||
stp_state_set(port, 0b01);
|
||||
stp_state_set(port, STP_ST_BLOCKING);
|
||||
port_timers[port] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
||||
return;
|
||||
@@ -563,9 +698,35 @@ void stp_timers(void) __banked
|
||||
/* Refill the per-port tx budgets once per second (tx hold count) */
|
||||
if (++stp_sec_tick >= STP_HZ) {
|
||||
stp_sec_tick = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++)
|
||||
stp_tx_budget[stp_i] = stp_txhold;
|
||||
|
||||
stp_lag_map();
|
||||
if (stp_map_dirty) {
|
||||
stp_map_dirty = 0;
|
||||
for (stp_i = 0; stp_i < STP_LAG_BASE; stp_i++) {
|
||||
if (stp_i < machine.min_port || stp_i > machine.max_port)
|
||||
continue;
|
||||
if (stp_ent_of[stp_i] != stp_i) {
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
} else {
|
||||
stp_ent_apply(stp_i);
|
||||
}
|
||||
}
|
||||
for (stp_i = STP_LAG_BASE; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (stp_lag_mask[stp_i - STP_LAG_BASE]) {
|
||||
stp_ent_apply(stp_i);
|
||||
} else {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
}
|
||||
}
|
||||
if (stp_root_port != 0xff && !stp_ent_active(stp_root_port))
|
||||
stp_claim_root();
|
||||
}
|
||||
|
||||
/* Link supervision. Without this the state machine never learns
|
||||
* that a port lost carrier: it keeps the port in forwarding, keeps
|
||||
* announcing on it, and never flushes what was learned behind it -
|
||||
@@ -574,14 +735,26 @@ void stp_timers(void) __banked
|
||||
* of the 50 Hz tick. */
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
stp_link_now = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
{
|
||||
__xdata static uint16_t eff;
|
||||
eff = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
if ((stp_link_now >> stp_i) & 1)
|
||||
eff |= (uint16_t)1 << stp_ent_of[stp_i];
|
||||
stp_link_now = eff;
|
||||
}
|
||||
if (stp_link_now != stp_link_prev) {
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port))
|
||||
continue;
|
||||
if (stp_i < STP_PORTS && stp_ent_of[stp_i] != stp_i)
|
||||
continue;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
continue;
|
||||
if (!((stp_link_now ^ stp_link_prev) >> stp_i & 1))
|
||||
continue;
|
||||
/* Either way the port must stop forwarding first. */
|
||||
stp_state_set(stp_i, 0b01);
|
||||
stp_state_set(stp_i, STP_ST_BLOCKING);
|
||||
if ((stp_link_now >> stp_i) & 1) {
|
||||
/* Carrier back: re-run the listen period rather than
|
||||
* forwarding straight away - the segment may have been
|
||||
@@ -600,8 +773,8 @@ void stp_timers(void) __banked
|
||||
}
|
||||
}
|
||||
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (!stp_ent_active(stp_i) || !(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
continue;
|
||||
|
||||
if (stp_bpdu_age[stp_i] < 0xffff)
|
||||
@@ -626,7 +799,7 @@ void stp_timers(void) __banked
|
||||
if (port_timers[stp_i]) {
|
||||
if (!--port_timers[stp_i]) {
|
||||
stp_loop_held[stp_i] = 0;
|
||||
stp_state_set(stp_i, 0b11);
|
||||
stp_state_set(stp_i, STP_ST_FORWARDING);
|
||||
print_string("STP: port forwarding ");
|
||||
print_port_nl(stp_i);
|
||||
stp_topology_change(stp_i);
|
||||
@@ -637,7 +810,7 @@ void stp_timers(void) __banked
|
||||
* host-facing, go to forwarding without the full wait. */
|
||||
port_timers[stp_i] = 0;
|
||||
stp_pflags[stp_i] |= STP_PF_OPEREDGE;
|
||||
stp_state_set(stp_i, 0b11);
|
||||
stp_state_set(stp_i, STP_ST_FORWARDING);
|
||||
print_string("STP: edge port forwarding ");
|
||||
print_port_nl(stp_i);
|
||||
}
|
||||
@@ -667,7 +840,12 @@ void stp_defaults(void) __banked
|
||||
stp_fwddelay_s = 15;
|
||||
stp_rstp = 1;
|
||||
stp_txhold = 6;
|
||||
for (stp_i = 0; stp_i < 10; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_PORTS; stp_i++)
|
||||
stp_ent_of[stp_i] = stp_i;
|
||||
for (stp_i = 0; stp_i < STP_LAG_COUNT; stp_i++)
|
||||
stp_lag_mask[stp_i] = 0;
|
||||
stp_map_dirty = 0;
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
/* enabled, auto-edge on: host-facing ports go forwarding after
|
||||
* 3 s of BPDU silence instead of the full forward delay */
|
||||
stp_pflags[stp_i] = STP_PF_ENABLED | STP_PF_AUTOEDGE;
|
||||
@@ -714,25 +892,34 @@ static void stp_fdb_update(__xdata uint16_t pmask)
|
||||
void stp_setup(void) __banked
|
||||
{
|
||||
print_string("Enabling STP: ");
|
||||
stp_lag_map();
|
||||
sfr_data[0] = sfr_data[1] = sfr_data[2] = sfr_data[3] = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
stp_bpdu_age[stp_i] = 0;
|
||||
stp_tx_budget[stp_i] = stp_txhold;
|
||||
stp_tx_count[stp_i] = 0;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED) || (stp_pflags[stp_i] & STP_PF_ADMEDGE)) {
|
||||
port_timers[stp_i] = 0;
|
||||
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
||||
if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port))
|
||||
continue;
|
||||
if (stp_i >= STP_LAG_BASE && !stp_lag_mask[stp_i - STP_LAG_BASE])
|
||||
continue;
|
||||
if (stp_i < STP_PORTS && stp_ent_of[stp_i] != stp_i)
|
||||
continue;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED)
|
||||
|| (stp_pflags[stp_i] & STP_PF_ADMEDGE)) {
|
||||
/* not participating, or admin edge: forwarding immediately */
|
||||
if (stp_pflags[stp_i] & STP_PF_ADMEDGE)
|
||||
stp_pflags[stp_i] |= STP_PF_OPEREDGE;
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b11 << ((stp_i << 1) & 0x7));
|
||||
stp_state_bits(stp_i, STP_ST_FORWARDING);
|
||||
port_timers[stp_i] = 0;
|
||||
} else {
|
||||
/* listen first: blocking until the forward-delay expires */
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b01 << ((stp_i << 1) & 0x7));
|
||||
stp_state_bits(stp_i, STP_ST_BLOCKING);
|
||||
port_timers[stp_i] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
}
|
||||
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
||||
}
|
||||
sfr_data[1] |= 0x0c; // Do not block the CPU port (bits 3:2 of byte 1 = port 9)
|
||||
reg_write_m(RTL837X_MSTP_STATES);
|
||||
@@ -752,7 +939,11 @@ void stp_setup(void) __banked
|
||||
/* Seed the carrier bitmap, so turning STP on does not report every
|
||||
* port that was already down as a fresh topology change. */
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
stp_link_prev = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
stp_link_now = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
stp_link_prev = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
if ((stp_link_now >> stp_i) & 1)
|
||||
stp_link_prev |= (uint16_t)1 << stp_ent_of[stp_i];
|
||||
|
||||
stp_claim_root();
|
||||
|
||||
@@ -767,7 +958,9 @@ void stp_off(void) __banked
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
// Set STP port state to forwarding
|
||||
// States are: 00 disable, 01 blocking, 10 learning, 11 forwarding
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b11 << ((stp_i << 1) & 0x7));
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(STP_ST_FORWARDING << ((stp_i << 1) & 0x7));
|
||||
}
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
@@ -782,7 +975,7 @@ void stp_off(void) __banked
|
||||
|
||||
void stp_parse(void) __banked __reentrant
|
||||
{
|
||||
uint8_t port;
|
||||
uint8_t ent;
|
||||
|
||||
if (cmd_compare(1, "on")) {
|
||||
print_string("STP enabled\n");
|
||||
@@ -803,35 +996,50 @@ void stp_parse(void) __banked __reentrant
|
||||
if (cmd_words_len < 3)
|
||||
goto err;
|
||||
|
||||
if (cmd_compare(1, "port")) {
|
||||
if (cmd_compare(1, "ent") || cmd_compare(1, "lag")) {
|
||||
stp_lag_map();
|
||||
if (cmd_words_len < 4)
|
||||
goto err;
|
||||
if (cmd_compare(1, "lag")) {
|
||||
if (!atoi_byte(cmd_words_b[2]))
|
||||
goto err;
|
||||
if (!atoi_results_u8 || atoi_results_u8 > STP_LAG_COUNT)
|
||||
goto err;
|
||||
ent = STP_LAG_BASE + atoi_results_u8 - 1;
|
||||
} else {
|
||||
if (!cmd_parse_port_separator(cmd_words_b[2]))
|
||||
goto err;
|
||||
port = atoi_results_u8;
|
||||
ent = atoi_results_u8;
|
||||
if (stp_ent_of[ent] != ent) {
|
||||
print_string("Port belongs to a LAG, configure it as lag ");
|
||||
print_byte(stp_ent_of[ent] - STP_LAG_BASE + 1);
|
||||
write_char('\n');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cmd_words_len < 5 && !cmd_compare(3, "on") && !cmd_compare(3, "off"))
|
||||
goto err;
|
||||
if (cmd_compare(3, "on")) {
|
||||
stp_pflags[port] |= STP_PF_ENABLED;
|
||||
stp_pflags[port] &= ~STP_PF_TRIPPED;
|
||||
stp_pflags[ent] |= STP_PF_ENABLED;
|
||||
stp_pflags[ent] &= ~STP_PF_TRIPPED;
|
||||
if (stp_enabled) { /* (re)join: listen first */
|
||||
stp_state_set(port, 0b01);
|
||||
port_timers[port] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
stp_state_set(ent, STP_ST_BLOCKING);
|
||||
port_timers[ent] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
}
|
||||
} else if (cmd_compare(3, "off")) {
|
||||
stp_pflags[port] &= ~STP_PF_ENABLED;
|
||||
stp_pflags[ent] &= ~STP_PF_ENABLED;
|
||||
if (stp_enabled)
|
||||
stp_state_set(port, 0b11); /* plain forwarding */
|
||||
stp_state_set(ent, STP_ST_FORWARDING); /* plain forwarding */
|
||||
} else if (cmd_compare(3, "edge")) {
|
||||
/* Also drop the *operational* edge flag: it is what exempts the
|
||||
* port from topology changes and lets it skip the listen period,
|
||||
* ent from topology changes and lets it skip the listen period,
|
||||
* so leaving it set would keep the old behaviour until the next
|
||||
* "stp off"/"stp on". An admin edge is operational immediately. */
|
||||
stp_pflags[port] &= ~(STP_PF_ADMEDGE | STP_PF_AUTOEDGE | STP_PF_OPEREDGE);
|
||||
stp_pflags[ent] &= ~(STP_PF_ADMEDGE | STP_PF_AUTOEDGE | STP_PF_OPEREDGE);
|
||||
if (cmd_compare(4, "on"))
|
||||
stp_pflags[port] |= STP_PF_ADMEDGE | STP_PF_OPEREDGE;
|
||||
stp_pflags[ent] |= STP_PF_ADMEDGE | STP_PF_OPEREDGE;
|
||||
else if (cmd_compare(4, "auto"))
|
||||
stp_pflags[port] |= STP_PF_AUTOEDGE;
|
||||
stp_pflags[ent] |= STP_PF_AUTOEDGE;
|
||||
else if (!cmd_compare(4, "off"))
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "cost")) {
|
||||
@@ -848,14 +1056,14 @@ void stp_parse(void) __banked __reentrant
|
||||
}
|
||||
if (stp_cost_scratch > 200000000UL)
|
||||
goto err;
|
||||
stp_pcost[port] = stp_cost_scratch;
|
||||
stp_pcost[ent] = stp_cost_scratch;
|
||||
} else if (cmd_compare(3, "p2p")) {
|
||||
if (cmd_compare(4, "auto"))
|
||||
stp_pp2p[port] = 0;
|
||||
stp_pp2p[ent] = 0;
|
||||
else if (cmd_compare(4, "on"))
|
||||
stp_pp2p[port] = 1;
|
||||
stp_pp2p[ent] = 1;
|
||||
else if (cmd_compare(4, "off"))
|
||||
stp_pp2p[port] = 2;
|
||||
stp_pp2p[ent] = 2;
|
||||
else
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "prio")) {
|
||||
@@ -863,20 +1071,20 @@ void stp_parse(void) __banked __reentrant
|
||||
goto err;
|
||||
if (atoi_results_u8 > 240 || (atoi_results_u8 & 0x0f))
|
||||
goto err;
|
||||
stp_pprio[port] = atoi_results_u8;
|
||||
stp_pprio[ent] = atoi_results_u8;
|
||||
} else if (cmd_compare(3, "guard")) {
|
||||
stp_pflags[port] &= ~(STP_PF_BPDUGUARD | STP_PF_ROOTGUARD);
|
||||
stp_pflags[ent] &= ~(STP_PF_BPDUGUARD | STP_PF_ROOTGUARD);
|
||||
if (cmd_compare(4, "bpdu"))
|
||||
stp_pflags[port] |= STP_PF_BPDUGUARD;
|
||||
stp_pflags[ent] |= STP_PF_BPDUGUARD;
|
||||
else if (cmd_compare(4, "root"))
|
||||
stp_pflags[port] |= STP_PF_ROOTGUARD;
|
||||
stp_pflags[ent] |= STP_PF_ROOTGUARD;
|
||||
else if (!cmd_compare(4, "none"))
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "filter")) {
|
||||
if (cmd_compare(4, "on"))
|
||||
stp_pflags[port] |= STP_PF_FILTER;
|
||||
stp_pflags[ent] |= STP_PF_FILTER;
|
||||
else if (cmd_compare(4, "off"))
|
||||
stp_pflags[port] &= ~STP_PF_FILTER;
|
||||
stp_pflags[ent] &= ~STP_PF_FILTER;
|
||||
else
|
||||
goto err;
|
||||
} else {
|
||||
@@ -926,5 +1134,5 @@ void stp_parse(void) __banked __reentrant
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9> on|off|edge|cost|prio|guard|filter ...\n");
|
||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | ent <1-9>|lag <1-4> on|off|edge|cost|prio|guard|filter ...\n");
|
||||
}
|
||||
+18
-8
@@ -2,6 +2,7 @@
|
||||
#define _RTL837X_STP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
void stp_in(void) __banked;
|
||||
void stp_setup(void) __banked;
|
||||
void stp_timers(void) __banked;
|
||||
@@ -12,6 +13,11 @@ void stp_defaults(void) __banked;
|
||||
/* Tick rate of stp_timers(), also used by the web UI. */
|
||||
#define STP_HZ 50
|
||||
|
||||
#define STP_PORTS (CPU_PORT + 1)
|
||||
#define STP_LAG_BASE STP_PORTS
|
||||
#define STP_LAG_COUNT 4
|
||||
#define STP_ENTITIES (STP_LAG_BASE + STP_LAG_COUNT)
|
||||
|
||||
/* Bridge identifier as carried in a BPDU (priority, extension, MAC). */
|
||||
struct bridge {
|
||||
uint8_t prio;
|
||||
@@ -36,15 +42,19 @@ extern __xdata uint8_t stp_txhold;
|
||||
#define STP_PF_OPEREDGE 0x40 /* runtime: port went forwarding as an edge */
|
||||
#define STP_PF_TRIPPED 0x80 /* runtime: disabled by BPDU guard */
|
||||
|
||||
extern __xdata uint8_t stp_pflags[10];
|
||||
extern __xdata uint32_t stp_pcost[10];
|
||||
extern __xdata uint8_t stp_pprio[10];
|
||||
extern __xdata uint8_t stp_pp2p[10];
|
||||
extern __xdata uint8_t stp_pflags[STP_ENTITIES];
|
||||
extern __xdata uint32_t stp_pcost[STP_ENTITIES]; /* path cost; 0 = auto (20000) */
|
||||
extern __xdata uint8_t stp_pprio[STP_ENTITIES];
|
||||
extern __xdata uint8_t stp_pp2p[STP_ENTITIES];
|
||||
extern __xdata uint8_t stp_ent_of[10]; /* the STP entity a port answers to: itself, or its lag */
|
||||
extern __xdata uint16_t stp_lag_mask[STP_LAG_COUNT]; /* member ports of each lag; 0 = not part of STP */
|
||||
|
||||
extern __xdata struct bridge stp_dbridge[10];
|
||||
extern __xdata uint16_t stp_dpid[10];
|
||||
extern __xdata uint32_t stp_dcost[10];
|
||||
extern __xdata uint16_t stp_bpdu_age[10];
|
||||
/* Last-heard designated info per port (from received BPDUs); consult
|
||||
* stp_bpdu_age to decide whether it is still current. */
|
||||
extern __xdata struct bridge stp_dbridge[STP_ENTITIES];
|
||||
extern __xdata uint16_t stp_dpid[STP_ENTITIES];
|
||||
extern __xdata uint32_t stp_dcost[STP_ENTITIES];
|
||||
extern __xdata uint16_t stp_bpdu_age[STP_ENTITIES]; /* ticks since a BPDU was heard */
|
||||
|
||||
extern __xdata struct bridge root_bridge;
|
||||
extern __xdata uint32_t root_bridge_cost;
|
||||
|
||||
+16
-624
@@ -26,6 +26,8 @@
|
||||
#include "phy.h"
|
||||
#include "syslog.h"
|
||||
#include "httpd/page_impl.h"
|
||||
#include "boot.h"
|
||||
#include "sfp.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint32_t flash_size;
|
||||
@@ -33,8 +35,6 @@ extern __xdata uint32_t flash_size;
|
||||
extern __xdata uint16_t crc_value;
|
||||
__xdata struct machine_runtime machine_detected;
|
||||
void crc16_bank1(__xdata uint8_t *v) __naked;
|
||||
void flash_default_config(void);
|
||||
void early_boot_handle_button(void);
|
||||
|
||||
// See setup_serial_timer1() for valid baudrate settings!
|
||||
#define SERIAL_BAUD_RATE 115200
|
||||
@@ -135,33 +135,10 @@ __code uint16_t bit_mask[16] = {
|
||||
__xdata uint8_t linkbits_last[4];
|
||||
__xdata uint8_t linkbits_last_p89;
|
||||
// Last known state of the SFP detection/Loss of Signal pins
|
||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||
__xdata uint8_t sfp_pins_last;
|
||||
__xdata char sfp_module_vendor[2][17];
|
||||
__xdata char sfp_module_model[2][17];
|
||||
__xdata char sfp_module_serial[2][17];
|
||||
__xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
__xdata bool button_last;
|
||||
__xdata uint8_t button_sec_counter_last;
|
||||
volatile __bit tx_buf_empty;
|
||||
|
||||
__code enum sfp_quirk {
|
||||
SFP_QUIRK_DDM = (1 << 0),
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
struct eth_in {
|
||||
struct uip_eth_addr dst;
|
||||
@@ -359,6 +336,19 @@ void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len)
|
||||
{
|
||||
__xdata const uint8_t *x = a;
|
||||
__xdata const uint8_t *y = b;
|
||||
while (len--) {
|
||||
if (*x != *y)
|
||||
return *x - *y;
|
||||
x++;
|
||||
y++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
@@ -931,33 +921,6 @@ void read_reg_timer(__xdata uint32_t * tmr)
|
||||
}
|
||||
|
||||
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode)
|
||||
{
|
||||
reg_read_m(RTL837X_REG_SDS_MODES);
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = 0;
|
||||
switch (sds) {
|
||||
case 0:
|
||||
sfr_mask_data(0, 0x1f, mode);
|
||||
break;
|
||||
case 1:
|
||||
sfr_mask_data(0, 0xe0, mode << 5);
|
||||
sfr_mask_data(1, 0x03, mode >> 3);
|
||||
break;
|
||||
case 2:
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
}
|
||||
if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
else
|
||||
sfr_data[2] &= 0x03;
|
||||
reg_write_m(RTL837X_REG_SDS_MODES);
|
||||
print_string("\nRTL837X_REG_SDS_MODES: ");
|
||||
print_reg(RTL837X_REG_SDS_MODES);
|
||||
print_string("\n");
|
||||
}
|
||||
|
||||
|
||||
// Delay for given number of ticks without doing housekeeping
|
||||
void delay(uint16_t t)
|
||||
{
|
||||
@@ -966,181 +929,6 @@ void delay(uint16_t t)
|
||||
PCON |= 1;
|
||||
}
|
||||
|
||||
void early_boot_handle_button(void)
|
||||
{
|
||||
if (machine.reset_pin == GPIO_NA)
|
||||
return;
|
||||
|
||||
gpio_input_setup(machine.reset_pin);
|
||||
|
||||
// Debounce after init
|
||||
delay(100);
|
||||
// If the button is not already held at boot, continue normally.
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
print_string("\n[Reset button held at boot]\n");
|
||||
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms
|
||||
const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms
|
||||
__xdata uint32_t start_ticks = ticks;
|
||||
__xdata uint32_t last_blink_step = start_ticks;
|
||||
__xdata uint8_t blink_step = 0;
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
while (!gpio_pin_test(machine.reset_pin)) {
|
||||
__xdata uint32_t held_ticks = ticks - start_ticks;
|
||||
|
||||
if (held_ticks > max_hold_ticks) {
|
||||
print_string("[Button held >30s at boot; continuing normal boot]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Double blink pattern while button is held:
|
||||
// ON (100ms), OFF (100ms), ON (100ms), OFF (500ms)
|
||||
__xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks;
|
||||
if ((ticks - last_blink_step) >= step_ticks) {
|
||||
blink_step = (blink_step + 1) & 0x3;
|
||||
set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF);
|
||||
last_blink_step = ticks;
|
||||
}
|
||||
|
||||
PCON |= 1;
|
||||
}
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
if ((ticks - start_ticks) >= min_hold_ticks) {
|
||||
print_string("[Button held 10s-30s at boot; restoring default config]\n");
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
flash_default_config();
|
||||
delay(3UL * SYS_TICK_HZ);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the SerDes of the SoC for a particular mode
|
||||
* to connect to an SFP module or a PHY
|
||||
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
|
||||
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
|
||||
* SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
|
||||
*/
|
||||
void sds_config(uint8_t sds, uint8_t mode)
|
||||
{
|
||||
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
|
||||
sds_config_mac(sds, mode);
|
||||
|
||||
if (mode == SDS_10GR || mode == SDS_QXGMII)
|
||||
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
|
||||
else
|
||||
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
|
||||
sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400
|
||||
sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02
|
||||
sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e
|
||||
sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002
|
||||
sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390
|
||||
sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f
|
||||
|
||||
uint8_t page = 0;
|
||||
uint16_t v = 0;
|
||||
|
||||
switch (mode) {
|
||||
case SDS_SGMII:
|
||||
case SDS_1000BX_FIBER:
|
||||
v = 0x0300;
|
||||
page = 0x24;
|
||||
break;
|
||||
case SDS_HISGMII:
|
||||
case SDS_HSG:
|
||||
v = 0x0200;
|
||||
page = 0x28;
|
||||
break;
|
||||
case SDS_10GR:
|
||||
case SDS_QXGMII:
|
||||
v = 0x0200;
|
||||
page = 0x2e;
|
||||
break;
|
||||
case SDS_100FX:
|
||||
v = 0x0200;
|
||||
page = 0x26;
|
||||
break;
|
||||
default:
|
||||
print_string("Error in SDS Mode\n");
|
||||
return;
|
||||
}
|
||||
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
|
||||
|
||||
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
|
||||
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
|
||||
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c
|
||||
sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217
|
||||
sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40
|
||||
sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1
|
||||
} else {
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080
|
||||
sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c
|
||||
sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217
|
||||
sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50
|
||||
sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG !
|
||||
}
|
||||
|
||||
sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443
|
||||
sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0
|
||||
|
||||
sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078
|
||||
sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401
|
||||
sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401
|
||||
sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401
|
||||
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
|
||||
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
|
||||
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
|
||||
|
||||
// RTL8261BE
|
||||
if (machine.n_10g && mode == SDS_QXGMII) {
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
return;
|
||||
}
|
||||
if (mode != SDS_QXGMII)
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
|
||||
if (mode == SDS_1000BX_FIBER) {
|
||||
sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020
|
||||
sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0
|
||||
sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d
|
||||
sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -1251,7 +1039,7 @@ void handle_rx(void)
|
||||
}
|
||||
} 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_arp_ipin();
|
||||
uip_input();
|
||||
if (uip_len) {
|
||||
// Add ethernet frame
|
||||
@@ -1290,85 +1078,6 @@ void handle_tx(void)
|
||||
}
|
||||
|
||||
|
||||
static inline uint8_t sfp_rate_to_sds_config(uint8_t rate)
|
||||
{
|
||||
if (rate == 0x1 || rate == 0x2)
|
||||
return SDS_100FX;
|
||||
if (rate == 0xc || rate == 0xd)
|
||||
return SDS_1000BX_FIBER;
|
||||
if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit
|
||||
return SDS_HSG;
|
||||
if (rate >= 0x62 && rate < 0x70)
|
||||
return SDS_10GR;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
bool sfp_print_info(uint8_t sfp)
|
||||
{
|
||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||
for (uint8_t i = 16; i < 64; i++) {
|
||||
if (!(i & 0xf) && !sfp_read_block(sfp, i, 16))
|
||||
return false;
|
||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||
continue;
|
||||
uint8_t c = sfp_buf[i & 0xf];
|
||||
if (c)
|
||||
write_char(c);
|
||||
}
|
||||
print_string("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
|
||||
bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant
|
||||
{
|
||||
if (!sfp_read_block(sfp, start, length))
|
||||
return false;
|
||||
|
||||
dst[length] = NUL;
|
||||
memcpy(dst, sfp_buf, length);
|
||||
|
||||
while (length > 0 && dst[--length] == ' ')
|
||||
dst[length] = NUL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sfp_get_info(uint8_t sfp)
|
||||
{
|
||||
if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16))
|
||||
return false;
|
||||
if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16))
|
||||
return false;
|
||||
|
||||
return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
|
||||
}
|
||||
|
||||
void sfp_apply_quirks(uint8_t sfp) __reentrant
|
||||
{
|
||||
sfp_quirks[sfp] = 0;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) {
|
||||
if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) {
|
||||
if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) {
|
||||
sfp_quirks[sfp] |= sfp_quirk_table[i].quirks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sfp_quirks[sfp] & SFP_QUIRK_DDM) {
|
||||
if (!(sfp_options[sfp] & 0x40)) {
|
||||
// The module reports that DDM is not implemented, but try a dummy read to confirm
|
||||
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
|
||||
if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) {
|
||||
sfp_options[sfp] |= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gpio_pin_test(uint8_t pin)
|
||||
{
|
||||
@@ -1376,87 +1085,6 @@ bool gpio_pin_test(uint8_t pin)
|
||||
return sfr_data[3-((pin >> 3) & 3)] & (1 << (pin & 7));
|
||||
}
|
||||
|
||||
/* Inititalize SFP GPIOs */
|
||||
void setup_sfp_gpio(void)
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_detect);
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_los);
|
||||
gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sfp_module_read(uint8_t sfp)
|
||||
{
|
||||
uint8_t rate;
|
||||
|
||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||
delay(100); // Delay, because some modules need time to wake up
|
||||
if (!sfp_read_block(sfp, 11, 2))
|
||||
return false;
|
||||
|
||||
rate = sfp_buf[1];
|
||||
if (sfp_speed[sfp] == SFP_SPEED_100M)
|
||||
rate = 0x1;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_1G)
|
||||
rate = 0xc;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_2G5)
|
||||
rate = 0x19;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_10G)
|
||||
rate = 0x69;
|
||||
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
|
||||
print_string(" Encoding: "); print_byte(sfp_buf[0]);
|
||||
print_string(" Module: ");
|
||||
if (!sfp_print_info(sfp))
|
||||
return false;
|
||||
print_string("\n");
|
||||
|
||||
if (!sfp_read_block(sfp, 92, 1))
|
||||
return false;
|
||||
sfp_options[sfp] = sfp_buf[0];
|
||||
if (!sfp_get_info(sfp))
|
||||
return false;
|
||||
|
||||
sfp_apply_quirks(sfp);
|
||||
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void handle_sfp(void)
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
|
||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
||||
if (!sfp_module_read(sfp)) {
|
||||
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_los)) {
|
||||
if (sfp_pins_last & (0x2 << (sfp << 2))) { // 0x2 0x08
|
||||
sfp_pins_last &= ~(0x02 << (sfp << 2));
|
||||
print_string("\n<SFP-RX OK> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & 0x2 << (sfp << 2))) {
|
||||
sfp_pins_last |= 0x02 << (sfp << 2);
|
||||
print_string("\n<SFP-RX LOS> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flash_default_config(void)
|
||||
{
|
||||
@@ -1668,19 +1296,6 @@ void setup_external_irqs(void)
|
||||
}
|
||||
|
||||
|
||||
void rtl8224_enable(void)
|
||||
{
|
||||
// Set Pin 4 low
|
||||
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
// Configure Pin as output
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
||||
delay(100);
|
||||
// Set pin 4 high
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set dividers for a chosen CPU frequency
|
||||
*/
|
||||
@@ -1803,55 +1418,6 @@ void phy_modify(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t mask, uin
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
void nic_setup(void)
|
||||
{
|
||||
// Enable NIC
|
||||
// r6040:00000100 R6040-00001100
|
||||
reg_bit_set(RTL837X_REG_HW_CONF, 0xc);
|
||||
|
||||
// This sets the size of the RX buffer, the filling level is in 0x7874
|
||||
// R7848-000004ff
|
||||
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
|
||||
|
||||
// R7844-000007fe
|
||||
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
|
||||
|
||||
// Configure NIC RX to receive various types of packets
|
||||
// RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17
|
||||
reg_read_m(RTL837X_REG_RX_CTRL);
|
||||
sfr_mask_data(3, 0xff, 0x04);
|
||||
sfr_mask_data(2, 0x03, 0);
|
||||
reg_write_m(RTL837X_REG_RX_CTRL);
|
||||
|
||||
// Enable NIC TX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_TX_CTRL, 0);
|
||||
|
||||
// Enable NIC RX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_RX_CTRL, 0);
|
||||
|
||||
// Drop packets with invalid CRC
|
||||
reg_bit_clear(RTL837X_REG_RX_CTRL, 2);
|
||||
|
||||
// R603c-00000200
|
||||
// CPU-port is CPU-Tag aware (bit 9)
|
||||
REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200);
|
||||
|
||||
// Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9)
|
||||
reg_read_m(RTL837X_REG_CPU_TAG);
|
||||
sfr_mask_data(0, 1, 1);
|
||||
sfr_mask_data(1, 3, 0);
|
||||
reg_write_m(RTL837X_REG_CPU_TAG);
|
||||
|
||||
// Force MAC mode of the CPU port (port 9)
|
||||
// r6368:00000194 R6368-00000197
|
||||
reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4);
|
||||
sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link
|
||||
reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4);
|
||||
|
||||
// Sequence number of TX packets
|
||||
tx_seq = 0;
|
||||
}
|
||||
|
||||
|
||||
void set_sys_led_state(uint8_t state)
|
||||
{
|
||||
@@ -1860,88 +1426,7 @@ void set_sys_led_state(uint8_t state)
|
||||
reg_write_m(RTL837X_REG_LED_MODE);
|
||||
}
|
||||
|
||||
void rtl8373_revision(void)
|
||||
{
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
delay(50);
|
||||
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n');
|
||||
sfr_mask_data(2, 0x0a, 0x00); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The SoC manages Link-State for steering the LEDs and can set PHY-settings
|
||||
* automatically through Realtek's SMI (Simple Managagement) Interface, a
|
||||
* proprietary version of MDIO which for example allows for more PHYs on the same
|
||||
* bus.
|
||||
* Configure polling via SMI and the interface setup during boot.
|
||||
*/
|
||||
void init_smi(void)
|
||||
{
|
||||
print_string("\ninit_switch called\n");
|
||||
|
||||
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
|
||||
* which are at port 8 and additionally at port 3 for a dual SFP device
|
||||
*/
|
||||
|
||||
// Default: 0x00005555
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x5555;
|
||||
if (machine.n_10g == 2) {
|
||||
// 0x00015555, only change the bytes that differs from the default.
|
||||
SFR_DATA_16 = 0x01;
|
||||
} else if (machine.n_sfp == 2)
|
||||
// 0x00005515
|
||||
SFR_DATA_0 = 0x15;
|
||||
reg_write(RTL837X_REG_SMI_MAC_TYPE);
|
||||
|
||||
// Configure polling of all PHYs by the MAC to detect link-state changes
|
||||
// Default: 0x000000ff
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x00ff;
|
||||
if (!machine_detected.isRTL8373) {
|
||||
if (machine.n_sfp == 2) {
|
||||
// 0x000000f0, only change the bytes that differs from the default.
|
||||
SFR_DATA_0 = 0xf0;
|
||||
} else {
|
||||
// 0x000001f8, only change the bytes that differs from the default.
|
||||
SFR_DATA_8 = 0x01;
|
||||
SFR_DATA_0 = 0xf8;
|
||||
}
|
||||
}
|
||||
reg_write(RTL837X_REG_SMI_PORT_POLLING);
|
||||
// Enable MDC
|
||||
reg_read_m(RTL837X_REG_SMI_CTRL);
|
||||
sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2
|
||||
reg_write_m(RTL837X_REG_SMI_CTRL);
|
||||
delay(50);
|
||||
|
||||
if (!machine_detected.isRTL8373) {
|
||||
// Change I2C addresses for SMI of the non-existent PHYs
|
||||
// r6450:000020e6 R6450-000000e6
|
||||
reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
sfr_mask_data(1, 0x7c, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
|
||||
// r644c:0a418820 R644c-0a400820
|
||||
reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
sfr_mask_data(2, 0x0f, 0);
|
||||
sfr_mask_data(1, 0x80, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
}
|
||||
|
||||
if (machine.n_10g == 2) {
|
||||
// Set address of second external PHY on port 8
|
||||
REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set up serial port 0 using Timer 1 as baudrate generator.
|
||||
@@ -1995,73 +1480,6 @@ void setup_serial_timer1(void)
|
||||
}
|
||||
|
||||
|
||||
void setup_i2c(void)
|
||||
{
|
||||
REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0);
|
||||
// Configure SFP EEPROM address (0x50) as I2C device address
|
||||
// Configure SFP readings address (0x51) as I2C device address
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff);
|
||||
|
||||
REG_SET(RTL837X_REG_I2C_CTRL2, 0);
|
||||
|
||||
// HW Control register, enable I2C depending on PIN configuration
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl);
|
||||
const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda);
|
||||
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
||||
switch (scl_bus) {
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 15-16 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x80, 0x80);
|
||||
sfr_mask_data(2, 0x01, 0x00);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 11-12 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x18, 0x08);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 7-8 0b01 -> SCL
|
||||
sfr_mask_data(0, 0x80, 0x80);
|
||||
sfr_mask_data(1, 0x01, 0x00);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n');
|
||||
}
|
||||
|
||||
switch (sda_bus) {
|
||||
case 4:
|
||||
// Bit 29 0b0 -> SDA
|
||||
sfr_mask_data(3, 0x20, 0x00);
|
||||
break;
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 17-18 0b01 -> SDA
|
||||
sfr_mask_data(2, 0x06, 0x02);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 13-14 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x60, 0x20);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 9-10 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x06, 0x02);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n');
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
}
|
||||
|
||||
|
||||
void check_and_flash_update_image(void)
|
||||
{
|
||||
flash_read_jedecid(); // This initializes also __xdata flash_size variable
|
||||
@@ -2147,32 +1565,6 @@ void check_and_flash_update_image(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Give the switch a name carrying the tail of its MAC, so several of them on
|
||||
* one network are distinguishable out of the box. Called after the startup
|
||||
* config has been replayed and returns at once if that config already set a
|
||||
* name, so a configured switch does no work for it (suggested in review).
|
||||
*
|
||||
* Written without a loop on purpose. Locals - counters and pointers alike -
|
||||
* land in the 8051's internal-RAM overlay, and on an image with LACP and STP
|
||||
* both enabled that overlay is exhausted: a loop here makes the linker fail
|
||||
* with "Could not get 8 consecutive bytes in internal RAM for area OSEG".
|
||||
* Moving the code into its own function does not help; the overlay is shared
|
||||
* across the whole image. Hoisting the locals to xdata does not help either,
|
||||
* because itohex() is inline and brings its own frame. */
|
||||
void set_hostname_default(void)
|
||||
{
|
||||
if (hostname[0] != NUL)
|
||||
return;
|
||||
|
||||
strcpy((__xdata uint8_t *)hostname, "RTLPlayground-");
|
||||
hostname[14] = hex[uip_ethaddr.addr[3] >> 4];
|
||||
hostname[15] = hex[uip_ethaddr.addr[3] & 0xf];
|
||||
hostname[16] = hex[uip_ethaddr.addr[4] >> 4];
|
||||
hostname[17] = hex[uip_ethaddr.addr[4] & 0xf];
|
||||
hostname[18] = hex[uip_ethaddr.addr[5] >> 4];
|
||||
hostname[19] = hex[uip_ethaddr.addr[5] & 0xf];
|
||||
hostname[20] = NUL;
|
||||
}
|
||||
|
||||
|
||||
void main(void)
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include <8051.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "phy.h"
|
||||
#include "boot.h"
|
||||
#include "sfp.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
|
||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||
__xdata uint8_t sfp_pins_last;
|
||||
__xdata char sfp_module_vendor[2][17];
|
||||
__xdata char sfp_module_model[2][17];
|
||||
__xdata char sfp_module_serial[2][17];
|
||||
__xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
|
||||
|
||||
__code enum sfp_quirk {
|
||||
SFP_QUIRK_DDM = (1 << 0),
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static inline uint8_t sfp_rate_to_sds_config(uint8_t rate)
|
||||
{
|
||||
if (rate == 0x1 || rate == 0x2)
|
||||
return SDS_100FX;
|
||||
if (rate == 0xc || rate == 0xd)
|
||||
return SDS_1000BX_FIBER;
|
||||
if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit
|
||||
return SDS_HSG;
|
||||
if (rate >= 0x62 && rate < 0x70)
|
||||
return SDS_10GR;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool sfp_print_info(uint8_t sfp) __banked
|
||||
{
|
||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||
for (uint8_t i = 16; i < 64; i++) {
|
||||
if (!(i & 0xf) && !sfp_read_block(sfp, i, 16))
|
||||
return false;
|
||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||
continue;
|
||||
uint8_t c = sfp_buf[i & 0xf];
|
||||
if (c)
|
||||
write_char(c);
|
||||
}
|
||||
print_string("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
|
||||
bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant
|
||||
{
|
||||
if (!sfp_read_block(sfp, start, length))
|
||||
return false;
|
||||
|
||||
dst[length] = NUL;
|
||||
memcpy(dst, sfp_buf, length);
|
||||
|
||||
while (length > 0 && dst[--length] == ' ')
|
||||
dst[length] = NUL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool sfp_get_info(uint8_t sfp) __banked
|
||||
{
|
||||
if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16))
|
||||
return false;
|
||||
if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16))
|
||||
return false;
|
||||
|
||||
return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sfp_apply_quirks(uint8_t sfp) __banked __reentrant
|
||||
{
|
||||
sfp_quirks[sfp] = 0;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) {
|
||||
if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) {
|
||||
if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) {
|
||||
sfp_quirks[sfp] |= sfp_quirk_table[i].quirks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sfp_quirks[sfp] & SFP_QUIRK_DDM) {
|
||||
if (!(sfp_options[sfp] & 0x40)) {
|
||||
// The module reports that DDM is not implemented, but try a dummy read to confirm
|
||||
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
|
||||
if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) {
|
||||
sfp_options[sfp] |= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Inititalize SFP GPIOs */
|
||||
void setup_sfp_gpio(void) __banked
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_detect);
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_los);
|
||||
gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool sfp_module_read(uint8_t sfp)
|
||||
{
|
||||
uint8_t rate;
|
||||
|
||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||
delay(100); // Delay, because some modules need time to wake up
|
||||
if (!sfp_read_block(sfp, 11, 2))
|
||||
return false;
|
||||
|
||||
rate = sfp_buf[1];
|
||||
if (sfp_speed[sfp] == SFP_SPEED_100M)
|
||||
rate = 0x1;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_1G)
|
||||
rate = 0xc;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_2G5)
|
||||
rate = 0x19;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_10G)
|
||||
rate = 0x69;
|
||||
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
|
||||
print_string(" Encoding: "); print_byte(sfp_buf[0]);
|
||||
print_string(" Module: ");
|
||||
if (!sfp_print_info(sfp))
|
||||
return false;
|
||||
print_string("\n");
|
||||
|
||||
if (!sfp_read_block(sfp, 92, 1))
|
||||
return false;
|
||||
sfp_options[sfp] = sfp_buf[0];
|
||||
if (!sfp_get_info(sfp))
|
||||
return false;
|
||||
|
||||
sfp_apply_quirks(sfp);
|
||||
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void handle_sfp(void) __banked
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
|
||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
||||
if (!sfp_module_read(sfp)) {
|
||||
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_los)) {
|
||||
if (sfp_pins_last & (0x2 << (sfp << 2))) { // 0x2 0x08
|
||||
sfp_pins_last &= ~(0x02 << (sfp << 2));
|
||||
print_string("\n<SFP-RX OK> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & 0x2 << (sfp << 2))) {
|
||||
sfp_pins_last |= 0x02 << (sfp << 2);
|
||||
print_string("\n<SFP-RX LOS> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SFP_H
|
||||
#define SFP_H
|
||||
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata char sfp_module_vendor[2][17];
|
||||
extern __xdata char sfp_module_model[2][17];
|
||||
extern __xdata char sfp_module_serial[2][17];
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
extern __xdata uint8_t sfp_speed[2];
|
||||
extern __xdata uint8_t sfp_quirks[2];
|
||||
|
||||
bool sfp_print_info(uint8_t sfp) __banked;
|
||||
bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant;
|
||||
bool sfp_get_info(uint8_t sfp) __banked;
|
||||
void sfp_apply_quirks(uint8_t sfp) __banked __reentrant;
|
||||
void setup_sfp_gpio(void) __banked;
|
||||
void handle_sfp(void) __banked;
|
||||
|
||||
#endif
|
||||
+12
-10
@@ -221,17 +221,17 @@ int addidx(const char *name, int addr, int len)
|
||||
/*
|
||||
* Replaces calls of the type #{function} in .html files being added
|
||||
* It is assumed that the possibly expanded string will fit into the buffer
|
||||
* Returns the new length of the string
|
||||
* Takes the length of the data and returns its new length
|
||||
*/
|
||||
int replaceCalls(int pos)
|
||||
int replaceCalls(int pos, int len)
|
||||
{
|
||||
int i = 0;
|
||||
char function_buf[256];
|
||||
|
||||
while (buffer[pos + i]) {
|
||||
if ((buffer[pos + i]) == '#' && (buffer[pos + i + 1] == '{')) {
|
||||
while (i < len) {
|
||||
if (buffer[pos + i] == '#' && i + 1 < len && buffer[pos + i + 1] == '{') {
|
||||
int j = 2;
|
||||
while (buffer[pos + i + j]) {
|
||||
while (i + j < len) {
|
||||
if (buffer[pos + i + j] == '}')
|
||||
break;
|
||||
function_buf[j - 2] = buffer[pos + i + j];
|
||||
@@ -244,12 +244,13 @@ int replaceCalls(int pos)
|
||||
|
||||
}
|
||||
function_buf[j - 2] = '\0';
|
||||
if (!buffer[pos + i + j])
|
||||
return i + j;
|
||||
if (i + j >= len)
|
||||
return len;
|
||||
// Because the buffers overlap we cannot use strcpy
|
||||
memmove(&buffer[pos + i + 5], &buffer[pos + i + j], strlen(&buffer[pos + i + j]) + 1);
|
||||
memmove(&buffer[pos + i + 5], &buffer[pos + i + j], len - (i + j));
|
||||
sprintf(&buffer[pos + i + 2], "%03d", callNum);
|
||||
buffer[pos + i + 5] = '}';
|
||||
len -= j - 5;
|
||||
i += 6;
|
||||
fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, " %s,\n", function_buf);
|
||||
xbuf_p += snprintf(&xbuf[xbuf_p], DEF_SIZE - xbuf_p, "extern uint16_t %s(void);\n", function_buf);
|
||||
@@ -258,7 +259,7 @@ int replaceCalls(int pos)
|
||||
i++;
|
||||
}
|
||||
|
||||
return strlen(&buffer[pos]);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -356,6 +357,7 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
|
||||
size_t data_read = addfile(pathbuffer, addr);
|
||||
size_t file_len = data_read;
|
||||
if (data_read) {
|
||||
if (arguments.add_zero) {
|
||||
/* NUL-terminate the data so the file table and the
|
||||
@@ -367,7 +369,7 @@ int main(int argc, char **argv)
|
||||
printf("Data inserted from %s at 0x%x, size: %ld\n", pathbuffer, addr, data_read);
|
||||
}
|
||||
int old_len = data_read;
|
||||
data_read = replaceCalls(addr);
|
||||
data_read = replaceCalls(addr, file_len);
|
||||
if (old_len > data_read)
|
||||
memset(buffer + addr + data_read, 0, old_len - data_read);
|
||||
if (arguments.gzip)
|
||||
|
||||
+2
-6
@@ -239,12 +239,9 @@ uip_arp_update(__xdata u16_t * __xdata ipaddr, __xdata struct uip_eth_addr * __x
|
||||
* variable uip_len.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if 0
|
||||
void
|
||||
uip_arp_ipin(void)
|
||||
uip_arp_ipin(void) __banked
|
||||
{
|
||||
uip_len -= sizeof(struct uip_eth_hdr);
|
||||
|
||||
/* Only insert/update an entry if the source IP address of the
|
||||
incoming IP packet comes from a host on the local network. */
|
||||
if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
|
||||
@@ -255,11 +252,10 @@ uip_arp_ipin(void)
|
||||
(uip_hostaddr[1] & uip_netmask[1])) {
|
||||
return;
|
||||
}
|
||||
uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
|
||||
uip_arp_update(IPBUF->srcipaddr, &(BUF->ethhdr.src));
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* 0 */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* ARP processing for incoming ARP packets.
|
||||
|
||||
+1
-2
@@ -78,8 +78,7 @@ void uip_arp_init(void) __banked;
|
||||
inserts a new mapping if none exists. The function assumes that an
|
||||
IP packet with an Ethernet header is present in the uip_buf buffer
|
||||
and that the length of the packet is in the uip_len variable. */
|
||||
/*void uip_arp_ipin(void);*/
|
||||
#define uip_arp_ipin()
|
||||
void uip_arp_ipin(void) __banked;
|
||||
|
||||
/* The uip_arp_arpin() should be called when an ARP packet is received
|
||||
by the Ethernet driver. This function also assumes that the
|
||||
|
||||
Reference in new issue
Block a user