mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Merge upstream/main into feat/webui-compression
Resolve the conflicts against the 41 upstream commits since 52692d0:
- Makefile: keep the upstream parallel-build fixes (grouped html_data
target with order-only deps, create_build_dir, crtbank, deterministic
BUILD_DATE, atomic version.h write) and keep the minify + gzip
pipeline (-z, html_min, .css/.ico in the html file list) on top.
- html: l2.js stays removed; port the upstream L2 fixes into the
single-page main.js (walkL2() with empty-reply and 4096-entry cap
handling, 3 retries on error). The L2 poll now re-schedules itself
after each walk and stops when the section is hidden.
- httpd/httpd.c merged cleanly (gzip Content-Encoding alongside the
upstream GET walk bound and counters.json port check).
- doc/webui-compression.md: describe the upstream version.h write.
Verified: KP_9000_6XHML_X2 and PCB_K0402WS_V3 build sequentially and
with make -j8; all 8 embedded files decompress byte-identically;
httpd_sim serves main.js/index.html and the L2 JSON endpoint.
This commit is contained in:
commit
37eefb4b35
20 files changed
+301
-143
No files matched your search
@@ -32,6 +32,17 @@ endif
|
||||
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
|
||||
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
|
||||
|
||||
# Deterministic build date: honor SOURCE_DATE_EPOCH, else the HEAD commit date,
|
||||
# else wall-clock (no-git fallback). Keeps same-commit builds byte-identical
|
||||
# (BUILD_DATE is baked into the image and covered by the trailing CRC).
|
||||
SOURCE_DATE_EPOCH ?= $(shell git show -s --format=%ct HEAD 2>/dev/null)
|
||||
ifeq ($(SOURCE_DATE_EPOCH),)
|
||||
BUILD_DATE := $(shell date +"%Y-%m-%d %H:%M:%S")
|
||||
else
|
||||
BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/dev/null \
|
||||
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
|
||||
endif
|
||||
|
||||
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
|
||||
|
||||
create_build_dir:
|
||||
@@ -87,18 +98,14 @@ html_min: $(HTML)
|
||||
mkdir -p $(HTML_MIN)
|
||||
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
|
||||
|
||||
html_data.c html_data.h: $(HTML) tools/output/fileadder html_min
|
||||
html_data.c html_data.h &: $(HTML) | tools html_min
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
|
||||
# httpd.c includes html_data.h; declare it explicitly so a parallel
|
||||
# build (-j) does not compile httpd before the header is generated.
|
||||
$(BUILDDIR)/httpd/httpd.rel: html_data.h
|
||||
|
||||
$(VERSION_HEADER):
|
||||
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
|
||||
@echo "#define VERSION_H" >> $(VERSION_HEADER)
|
||||
@echo "#define VERSION_SW \"$(VERSION_EXTENSION)\"" >> $(VERSION_HEADER)
|
||||
@echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
|
||||
@echo "#endif" >> $(VERSION_HEADER)
|
||||
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
|
||||
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
|
||||
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
|
||||
"#endif" > $(VERSION_HEADER)
|
||||
|
||||
httpd: html_data.h
|
||||
|
||||
@@ -113,20 +120,20 @@ distclean:
|
||||
-rm -f html_data.c html_data.h $(VERSION_HEADER)
|
||||
-rm -rf $(BUILDDIR)
|
||||
|
||||
$(BUILDDIR)/%.rel: %.c
|
||||
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
|
||||
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/%.rel: %.asm
|
||||
$(BUILDDIR)/%.rel: %.asm | create_build_dir
|
||||
${ASM} ${AFLAGS} -o $@ $<
|
||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||
|
||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel
|
||||
$(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 $@ $^
|
||||
|
||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||
objcopy --input-target=ihex -O binary $< $@
|
||||
|
||||
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img
|
||||
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools
|
||||
if [ -e $@ ]; then rm $@; fi
|
||||
tools/output/imagebuilder -i $^ $@
|
||||
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
@@ -135,7 +142,7 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
|
||||
tools/output/crc_calculator -u $@
|
||||
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
|
||||
|
||||
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
|
||||
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER) create_build_dir
|
||||
|
||||
.PHONY:
|
||||
machine_check:
|
||||
|
||||
+5
-2
@@ -40,8 +40,10 @@ void cmd_edit(void) __banked
|
||||
{
|
||||
while (l != sbuf_ptr) {
|
||||
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
|
||||
if (cmd_line_len >= CMD_BUF_SIZE)
|
||||
continue;
|
||||
// Reserve one byte for the terminating NUL written on Enter. When the
|
||||
// line is full, drop the character but still fall through to advance the
|
||||
// serial-ring read pointer below; a 'continue' here would spin forever.
|
||||
if (cmd_line_len < CMD_BUF_SIZE - 1) {
|
||||
write_char(sbuf[l]);
|
||||
// Shift buffer to right
|
||||
for (uint8_t i = cmd_line_len; i > cursor; i--)
|
||||
@@ -55,6 +57,7 @@ void cmd_edit(void) __banked
|
||||
// Move backwards
|
||||
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||
write_char('\010'); // BS works like cursor-left
|
||||
}
|
||||
} else if (sbuf[l] == '\033') { // ESC-Sequence
|
||||
// Wait until we have at least 3 characters including the ESC character in the serial buffer
|
||||
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
|
||||
|
||||
+18
-6
@@ -250,8 +250,7 @@ void parse_lag(void)
|
||||
print_string("LAG status:\n");
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
write_char(' '); write_char('1' + i);
|
||||
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (i << 2));
|
||||
members = ((uint16_t)sfr_data[2]) << 8 | sfr_data[3];
|
||||
members = port_lag_members_get(i);
|
||||
if (!members) {
|
||||
print_string(" disabled\n");
|
||||
continue;
|
||||
@@ -274,7 +273,9 @@ void parse_lag(void)
|
||||
|
||||
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]]))
|
||||
goto err;
|
||||
group = cmd_buffer[cmd_words_b[1]] - '0';
|
||||
group = cmd_buffer[cmd_words_b[1]] - '1';
|
||||
if (group > 3) /* '0' wraps well past three, so one test does both ends */
|
||||
goto err;
|
||||
|
||||
uint8_t w = 2;
|
||||
while (w < cmd_words_len) {
|
||||
@@ -284,6 +285,8 @@ void parse_lag(void)
|
||||
port = cmd_buffer[cmd_words_b[w]] - '1';
|
||||
if (isnumber(cmd_buffer[cmd_words_b[w] + 1]))
|
||||
port = (port + 1) * 10 + cmd_buffer[cmd_words_b[w] + 1] - '1';
|
||||
if (port > 8) /* phys_to_log_port holds nine entries */
|
||||
goto err;
|
||||
port = machine.phys_to_log_port[port];
|
||||
} else {
|
||||
goto err;
|
||||
@@ -296,7 +299,7 @@ void parse_lag(void)
|
||||
port_lag_members_set(group, members);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: lag <lag> [port]...\n");
|
||||
print_string("Error: lag <1-4> [port]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +308,11 @@ void parse_lag_hash(void)
|
||||
__xdata uint8_t group;
|
||||
__xdata uint8_t hash = 0;
|
||||
|
||||
group = cmd_buffer[cmd_words_b[1]] - '0';
|
||||
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]]))
|
||||
goto err;
|
||||
group = cmd_buffer[cmd_words_b[1]] - '1';
|
||||
if (group > 3) /* '0' wraps well past three, so one test does both ends */
|
||||
goto err;
|
||||
|
||||
uint8_t w = 2;
|
||||
while (w < cmd_words_len) {
|
||||
@@ -331,6 +338,9 @@ void parse_lag_hash(void)
|
||||
w++;
|
||||
}
|
||||
port_lag_hash_set(group, hash);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: lag hash <1-4> [type]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1530,10 +1540,12 @@ void cmd_parser(void) __banked
|
||||
} else if (cmd_compare(0, "igmp")) {
|
||||
if (cmd_compare(1, "on"))
|
||||
igmp_enable();
|
||||
else if (cmd_compare(1, "off"))
|
||||
igmp_setup();
|
||||
else if (cmd_compare(1, "show"))
|
||||
igmp_show();
|
||||
else
|
||||
igmp_setup(); // Reverts to default with IP-MC being flooded
|
||||
print_string("Error: igmp on|off|show\n");
|
||||
} 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
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
.area HOME (CODE)
|
||||
.area GSINIT0 (CODE)
|
||||
.area GSINIT1 (CODE)
|
||||
.area GSINIT2 (CODE)
|
||||
.area GSINIT3 (CODE)
|
||||
.area GSINIT4 (CODE)
|
||||
.area GSINIT5 (CODE)
|
||||
.area GSINIT (CODE)
|
||||
.area GSFINAL (CODE)
|
||||
.area CSEG (CODE)
|
||||
|
||||
|
||||
.area HOME (CODE)
|
||||
|
||||
__sdcc_banked_call::
|
||||
push _PSBANK
|
||||
xch a,r0
|
||||
push a
|
||||
mov a,r1
|
||||
push a
|
||||
mov a,r2
|
||||
anl a,#0x1f
|
||||
mov _PSBANK, a
|
||||
xch a, r0
|
||||
ret
|
||||
|
||||
__sdcc_banked_ret::
|
||||
pop _PSBANK
|
||||
ret
|
||||
@@ -1,17 +0,0 @@
|
||||
.area GSFINAL (CODE)
|
||||
|
||||
__sdcc_banked_call::
|
||||
push _PSBANK
|
||||
xch a,r0
|
||||
push a
|
||||
mov a,r1
|
||||
push a
|
||||
mov a,r2
|
||||
anl a,#0x1f
|
||||
mov _PSBANK, a
|
||||
xch a, r0
|
||||
ret
|
||||
|
||||
__sdcc_banked_ret::
|
||||
pop _PSBANK
|
||||
ret
|
||||
@@ -41,6 +41,7 @@ __xdata uip_ipaddr_t server;
|
||||
#define DHCP_REBIND_LEN 4
|
||||
#define DHCP_CLIENT_ID 61
|
||||
#define DHCP_CLIENT_ID_LEN 7
|
||||
#define DHCP_HOSTNAME 12
|
||||
#define DHCP_REQUEST_IP 50
|
||||
#define DHCP_REQUEST_IP_LEN 4
|
||||
#define DHCP_PARAMS 55
|
||||
@@ -116,6 +117,20 @@ void dhcp_addopt_client_id(void)
|
||||
}
|
||||
|
||||
|
||||
void dhcp_addopt_hostname(void)
|
||||
{
|
||||
uint8_t len = 0;
|
||||
while (hostname[len])
|
||||
len++;
|
||||
if (!len)
|
||||
return;
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = len;
|
||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
|
||||
dhcp_state.opt_ptr += len;
|
||||
}
|
||||
|
||||
|
||||
void dhcp_addopt_request_ip(void)
|
||||
{
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
|
||||
@@ -152,6 +167,7 @@ void dhcp_send_discover(void)
|
||||
|
||||
dhcp_addopt_client_id();
|
||||
dhcp_addopt_request_ip();
|
||||
dhcp_addopt_hostname();
|
||||
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||
@@ -188,6 +204,7 @@ void dhcp_send_request(void)
|
||||
dhcp_addopt_client_id();
|
||||
dhcp_addopt_request_ip();
|
||||
dhcp_addopt_server_id();
|
||||
dhcp_addopt_hostname();
|
||||
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||
|
||||
@@ -92,7 +92,7 @@ The following shows the network configuration
|
||||
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
|
||||
source and destination ports into account, e.g. just use the default:
|
||||
```
|
||||
> lag 0 1 2
|
||||
> lag 1 1 2
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -75,8 +75,10 @@ JSON polling of the visible section).
|
||||
- `fileadder` terminates the embedded files with a NUL directly after the
|
||||
content (previously at `data_read + 1`), so the `strlen()`-based size
|
||||
computation no longer depends on uninitialised buffer content.
|
||||
- `version.h` is no longer `.PHONY`; every build previously rewrote it
|
||||
while a parallel build (`make -j`) could read a half-written copy.
|
||||
- `version.h` is now written by a single atomic `printf` (change from
|
||||
upstream) instead of five separate `echo`s, so a parallel build
|
||||
(`make -j`) can no longer read a half-written copy. It stays in
|
||||
`.PHONY` so it is regenerated on every build.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
+77
-42
@@ -934,6 +934,10 @@ function setSectionInterval(fn, ms) {
|
||||
function clearSectionIntervals() {
|
||||
sectionIntervals.forEach(function(t) { clearInterval(t); });
|
||||
sectionIntervals = [];
|
||||
if (l2Timer) {
|
||||
clearTimeout(l2Timer);
|
||||
l2Timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function showSection(name) {
|
||||
@@ -1650,10 +1654,7 @@ sectionInits.stat = function() {
|
||||
});
|
||||
};
|
||||
|
||||
var l2GetInterval;
|
||||
var l2Entries = [];
|
||||
var l2CurrentEntry = 0;
|
||||
|
||||
var l2Timer;
|
||||
|
||||
function l2CMP(a, b)
|
||||
{
|
||||
@@ -1744,7 +1745,6 @@ function fillL2(s)
|
||||
s = uniq(s);
|
||||
l2All = s;
|
||||
renderL2();
|
||||
l2Entries = [];
|
||||
}
|
||||
|
||||
function paintL2(tbl, s)
|
||||
@@ -1773,50 +1773,22 @@ function paintL2(tbl, s)
|
||||
}
|
||||
|
||||
function getL2() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var s = JSON.parse(xhttp.responseText);
|
||||
var s = s.map(function(e) {
|
||||
e.vlan = parseInt(e.vlan, 16);
|
||||
e.idx = parseInt(e.idx, 16);
|
||||
e.type = e.type == "s" ? t('l2_static') : t('l2_learned');
|
||||
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
|
||||
return e;
|
||||
walkL2(function(entries, ok) {
|
||||
if (ok) {
|
||||
for (var i = 0; i < entries.length; i++)
|
||||
entries[i].type = entries[i].type == "s" ? t('l2_static') : t('l2_learned');
|
||||
fillL2(entries);
|
||||
}
|
||||
var sec = document.getElementById('page-l2');
|
||||
if (sec && sec.style.display === 'block')
|
||||
l2Timer = setTimeout(getL2, 1000);
|
||||
});
|
||||
l2Entries.push(...s);
|
||||
if (l2Entries >= 4096) {
|
||||
l2Entries = [];
|
||||
l2CurrentEntry = 0;
|
||||
clearInterval(l2GetInterval);
|
||||
return;
|
||||
}
|
||||
var w = 0;
|
||||
for (var i = l2Entries.length-1; i > 0; i--) {
|
||||
if (l2Entries[0].idx == l2Entries[i].idx) {
|
||||
w = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (w) {
|
||||
l2CurrentEntry = 0;
|
||||
fillL2(l2Entries);
|
||||
} else {
|
||||
l2CurrentEntry = s[s.length-1].idx + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
|
||||
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||
}
|
||||
|
||||
sectionInits.l2 = function() {
|
||||
l2Entries = [];
|
||||
l2CurrentEntry = 0;
|
||||
update( () => {
|
||||
getL2();
|
||||
setSectionInterval(update, 2000);
|
||||
l2GetInterval = setSectionInterval(getL2, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2497,3 +2469,66 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
})
|
||||
.catch(error => console.error('Error fetching the data:', error));
|
||||
});
|
||||
|
||||
function walkL2(onDone)
|
||||
{
|
||||
var entries = [];
|
||||
var idx = 0;
|
||||
var tries = 0;
|
||||
|
||||
function retry() {
|
||||
if (++tries < 3) {
|
||||
setTimeout(page, 1000);
|
||||
return;
|
||||
}
|
||||
onDone(entries, false);
|
||||
}
|
||||
|
||||
function page() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState != 4)
|
||||
return;
|
||||
if (this.status != 200) {
|
||||
retry();
|
||||
return;
|
||||
}
|
||||
var s;
|
||||
try {
|
||||
s = JSON.parse(xhttp.responseText);
|
||||
} catch (err) {
|
||||
retry();
|
||||
return;
|
||||
}
|
||||
tries = 0;
|
||||
s = s.map(function(e) {
|
||||
e.vlan = parseInt(e.vlan, 16);
|
||||
e.idx = parseInt(e.idx, 16);
|
||||
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
|
||||
return e;
|
||||
});
|
||||
if (!s.length) {
|
||||
onDone(entries, true);
|
||||
return;
|
||||
}
|
||||
entries.push(...s);
|
||||
for (var i = entries.length - 1; i > 0; i--) {
|
||||
if (entries[0].idx == entries[i].idx) {
|
||||
onDone(entries, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (entries.length >= 4096) {
|
||||
onDone(entries, true);
|
||||
return;
|
||||
}
|
||||
idx = s[s.length - 1].idx + 1;
|
||||
setTimeout(page, 1000);
|
||||
};
|
||||
xhttp.open("GET", "/l2.json?idx=" + idx, true);
|
||||
xhttp.timeout = 1500;
|
||||
sendXHTTP(xhttp);
|
||||
}
|
||||
|
||||
page();
|
||||
}
|
||||
+11
-2
@@ -640,7 +640,7 @@ void httpd_appcall(void)
|
||||
p += 4;
|
||||
scan_header(p);
|
||||
__xdata uint8_t *q = p;
|
||||
while (!is_separator(*p))
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p = '\0';
|
||||
dbg_string_x(q);
|
||||
@@ -664,7 +664,16 @@ void httpd_appcall(void)
|
||||
parse_short(q + 15);
|
||||
send_vlan(short_parsed);
|
||||
} else if (is_word(q, "/counters.json")) {
|
||||
send_counters(q[20]-'0');
|
||||
/* The port is one raw character of the request line and
|
||||
* indexes a nine entry table, so bound it here instead
|
||||
* of trusting the client to have sent a digit. Anything
|
||||
* below '0' wraps well past eight, so the one test
|
||||
* covers both ends. */
|
||||
uint8_t cport = q[20] - '0';
|
||||
if (cport > 8)
|
||||
send_bad_request();
|
||||
else
|
||||
send_counters(cport);
|
||||
} else if (is_word(q, "/eee.json")) {
|
||||
send_eee();
|
||||
} else if (is_word(q, "/bandwidth.json")) {
|
||||
|
||||
+24
-23
@@ -356,6 +356,7 @@ void send_l2(uint16_t idx)
|
||||
*/
|
||||
__xdata uint16_t entry = idx & 0xfff;
|
||||
__xdata uint16_t first_entry = 0xffff; // An illegal entry index
|
||||
__bit first = true;
|
||||
char_to_html('[');
|
||||
while (1) {
|
||||
entries_left--;
|
||||
@@ -369,9 +370,22 @@ void send_l2(uint16_t idx)
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
if ((sfr_data[0] & 0x20)) { // Check entry is valid
|
||||
__bit valid = (sfr_data[0] & 0x20) != 0;
|
||||
if (valid) {
|
||||
/* separator + 74-byte worst-case entry + closing "]" */
|
||||
if (slen + 76 > TCP_OUTBUF_SIZE)
|
||||
break;
|
||||
if (!first)
|
||||
char_to_html(',');
|
||||
first = false;
|
||||
|
||||
// VLAN, taken from the read above instead of reading the register twice
|
||||
slen += strtox(outbuf + slen, "{\"vlan\":\"");
|
||||
charhex_to_html(sfr_data[0] & 0x0f);
|
||||
byte_to_html(sfr_data[1]);
|
||||
|
||||
// MAC
|
||||
slen += strtox(outbuf + slen, "{\"mac\":\"");
|
||||
slen += strtox(outbuf + slen, "\",\"mac\":\"");
|
||||
byte_to_html(sfr_data[2]); char_to_html(':');
|
||||
byte_to_html(sfr_data[3]); char_to_html(':');
|
||||
port = (sfr_data[0] >> 6) & 0x3;
|
||||
@@ -381,12 +395,6 @@ void send_l2(uint16_t idx)
|
||||
byte_to_html(sfr_data[2]); char_to_html(':');
|
||||
byte_to_html(sfr_data[3]);
|
||||
|
||||
// VLAN
|
||||
slen += strtox(outbuf + slen, "\",\"vlan\":\"");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
charhex_to_html(sfr_data[0] & 0x0f);
|
||||
byte_to_html(sfr_data[1]);
|
||||
|
||||
// type
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
if (sfr_data[2] & 0x1)
|
||||
@@ -396,32 +404,26 @@ void send_l2(uint16_t idx)
|
||||
|
||||
port |= (sfr_data[3] & 0x3) << 2;
|
||||
itoa_html(port);
|
||||
}
|
||||
|
||||
// Index
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3];
|
||||
if (valid) {
|
||||
slen += strtox(outbuf + slen, ",\"idx\":\"");
|
||||
byte_to_html(entry >> 8);
|
||||
byte_to_html(entry);
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
}
|
||||
entry += 1; // We want the next entry following after the current entry
|
||||
} else {
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1;
|
||||
}
|
||||
if (first_entry == 0xffff) {
|
||||
char_to_html(',');
|
||||
|
||||
if (first_entry == 0xffff)
|
||||
first_entry = entry;
|
||||
} else {
|
||||
if (first_entry == entry || !entries_left) {
|
||||
char_to_html(']');
|
||||
else if (first_entry == entry || !entries_left)
|
||||
break;
|
||||
} else {
|
||||
char_to_html(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
char_to_html(']');
|
||||
}
|
||||
|
||||
|
||||
@@ -518,8 +520,7 @@ void send_lag(void)
|
||||
slen += strtox(outbuf + slen, "{\"lagNum\":");
|
||||
itoa_html(l);
|
||||
slen += strtox(outbuf + slen, ",\"members\":\"");
|
||||
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (l << 2));
|
||||
uint16_t ports = ((uint16_t)sfr_data[2] << 8) | sfr_data[3];
|
||||
uint16_t ports = port_lag_members_get(l);
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(!!(ports & 0x8000));
|
||||
ports <<= 1;
|
||||
|
||||
@@ -415,6 +415,7 @@ void machine_custom_init(void) { }
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "SWTGW218AS 8+1 Managed Switch",
|
||||
.isRTL8373 = 1,
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
|
||||
@@ -85,6 +85,7 @@ typedef struct machine {
|
||||
uint32_t led_sets[4][4];
|
||||
uint8_t led_mux_custom;
|
||||
uint8_t led_mux[28];
|
||||
uint32_t mac_flash_offset;
|
||||
};
|
||||
|
||||
typedef struct machine_runtime
|
||||
|
||||
+5
-7
@@ -16,6 +16,7 @@
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __xdata uint8_t igmpEnabled;
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
@@ -85,6 +86,7 @@ void igmp_setup(void) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
print_string("igmp_setup called\n");
|
||||
igmpEnabled = 0;
|
||||
// For now, forward all unkown IP-MC pkts (2 bits per port. 00: flood via floodmask, 01: drop, 10: trap, 11: to rport)
|
||||
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
|
||||
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
|
||||
@@ -96,11 +98,6 @@ void igmp_setup(void) __banked
|
||||
// Enable lookup of IPv4 MC addresses in table
|
||||
reg_bit_set(RTL837X_L2_CTRL, L2_CTRL_LUT_IPMC_HASH);
|
||||
|
||||
// Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping,
|
||||
// bits 16-24 configure max MC group used by that port. For now all protocols are flooded (01)
|
||||
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), 0x00ff7c15);
|
||||
|
||||
/* Configure per-port IGMP operations when protocol messages are received
|
||||
* bits 0-9 enable MC protocol snooping
|
||||
* bit 10: Enable dynamic router port learning
|
||||
@@ -135,6 +132,7 @@ void igmp_setup(void) __banked
|
||||
void igmp_enable(void) __banked
|
||||
{
|
||||
print_string("igmp_enable called\n");
|
||||
igmpEnabled = 1;
|
||||
// Configure trapping of unhandled IGMP protocol packets to CPU
|
||||
REG_SET(RTL837X_IGMP_TRAP_CFG, IGMP_CPU_PORT | IGMP_TRAP_PRIORITY);
|
||||
|
||||
@@ -223,7 +221,7 @@ void igmp_packet_handler(void) __banked
|
||||
#endif
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
memset(&entry, 0, sizeof(struct ipmc_table_entry));
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct ipmc_table_entry));
|
||||
// For IPv4 MC, the Source-IP is 0.0.0.0
|
||||
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
|
||||
// For IPv4 MC, the Destination-IP is the IPv4 MC address
|
||||
@@ -235,7 +233,7 @@ void igmp_packet_handler(void) __banked
|
||||
* yy = MC_IP[2]
|
||||
* zz = MC_IP[3]
|
||||
*/
|
||||
memset(&entry, 0, sizeof(struct l2mc_table_entry));
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct l2mc_table_entry));
|
||||
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
|
||||
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
|
||||
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
|
||||
|
||||
+24
-6
@@ -733,6 +733,19 @@ void port_rldp_on(__xdata uint16_t p_ms)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reads the member port bitmask of a Link Aggregation Group.
|
||||
* The groups have numbers 0-3; bit n is set when logical port n is a member.
|
||||
* The bitmask reflects what the hardware holds, so it covers groups set up
|
||||
* statically and groups a protocol brought up, without either having to say so.
|
||||
*/
|
||||
uint16_t port_lag_members_get(uint8_t lag) __banked
|
||||
{
|
||||
reg_read(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2));
|
||||
return ((uint16_t)SFR_DATA_8 << 8) | SFR_DATA_0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure LAGs
|
||||
* Sets the members via port bitmask of a given Link Aggregation Group
|
||||
@@ -744,11 +757,14 @@ void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banke
|
||||
{
|
||||
print_string("port_lag_members_set, lag: "); print_byte(lag); print_string(", members: "); print_short(members);
|
||||
write_char('\n');
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!\n");
|
||||
if (lag > 3) {
|
||||
print_string("Link aggregation group out of range\n");
|
||||
return;
|
||||
}
|
||||
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2));
|
||||
if (!(sfr_data[0] | sfr_data [1] | sfr_data [2] | sfr_data [3]))
|
||||
REG_SET(RTL837X_TRK_HASH_CTRL_BASE, LAG_HASH_DEFAULT);
|
||||
if (!(sfr_data[0] | sfr_data[1] | sfr_data[2])
|
||||
&& (sfr_data[3] == LAG_HASH_RESET || sfr_data[3] == 0))
|
||||
REG_SET(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), LAG_HASH_DEFAULT);
|
||||
REG_WRITE(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2), 0, 0, members >> 8, members & 0xff);
|
||||
}
|
||||
|
||||
@@ -761,8 +777,10 @@ void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked
|
||||
{
|
||||
print_string("port_lag_hash_set, lag: "); print_byte(lag); print_string(", hash: "); print_byte(hash_bits);
|
||||
write_char('\n');
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!\n");
|
||||
if (lag > 3) {
|
||||
print_string("Link aggregation group out of range\n");
|
||||
return;
|
||||
}
|
||||
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata u
|
||||
void port_mirror_del(void) __banked;
|
||||
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked;
|
||||
void port_l2_setup(void) __banked;
|
||||
uint16_t port_lag_members_get(uint8_t lag) __banked;
|
||||
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
|
||||
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked;
|
||||
void port_eee_enable_all(__xdata uint8_t speed) __banked;
|
||||
|
||||
+18
-8
@@ -232,6 +232,8 @@
|
||||
#define LAG_HASH_L4_SPORT 0x20
|
||||
#define LAG_HASH_L4_DPORT 0x40
|
||||
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC | LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT | LAG_HASH_L4_DPORT)
|
||||
#define LAG_HASH_RESET (LAG_HASH_SOURCE_PORT_NUMBER | LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC \
|
||||
| LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT)
|
||||
|
||||
/*
|
||||
* Port isolation
|
||||
@@ -305,32 +307,40 @@
|
||||
|
||||
#ifdef REGDBG
|
||||
|
||||
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
#define REG_SET(r, v) do { \
|
||||
SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
|
||||
SFR_DATA_0 = (v) & 0xff; \
|
||||
reg_write(r); \
|
||||
write_char('R'); print_byte(r >> 8); print_byte(r); write_char('-'); \
|
||||
print_byte(((v) >> 24) & 0xff); print_byte((v) >> 16 & 0xff); print_byte((v) >> 8 & 0xff); print_byte( (v) & 0xff); write_char(' ');
|
||||
print_byte(((v) >> 24) & 0xff); print_byte((v) >> 16 & 0xff); print_byte((v) >> 8 & 0xff); print_byte( (v) & 0xff); write_char(' '); \
|
||||
} while (0)
|
||||
|
||||
#define REG_WRITE(r, v24, v16, v8, v0) SFR_DATA_24 = (v24); \
|
||||
#define REG_WRITE(r, v24, v16, v8, v0) do { \
|
||||
SFR_DATA_24 = (v24); \
|
||||
SFR_DATA_16 = (v16); \
|
||||
SFR_DATA_8 = (v8); \
|
||||
SFR_DATA_0 = (v0); \
|
||||
reg_write(r); \
|
||||
write_char('R'); print_byte(r>>8); print_byte(r); write_char('-'); print_byte(v24); print_byte(v16); print_byte(v8); print_byte(v0); write_char(' ');
|
||||
write_char('R'); print_byte(r>>8); print_byte(r); write_char('-'); print_byte(v24); print_byte(v16); print_byte(v8); print_byte(v0); write_char(' '); \
|
||||
} while (0)
|
||||
#else
|
||||
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
#define REG_SET(r, v) do { \
|
||||
SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
|
||||
SFR_DATA_0 = (v) & 0xff; \
|
||||
reg_write(r);
|
||||
reg_write(r); \
|
||||
} while (0)
|
||||
|
||||
#define REG_WRITE(r, v24, v16, v8, v0) SFR_DATA_24 = (v24); \
|
||||
#define REG_WRITE(r, v24, v16, v8, v0) do { \
|
||||
SFR_DATA_24 = (v24); \
|
||||
SFR_DATA_16 = (v16); \
|
||||
SFR_DATA_8 = (v8); \
|
||||
SFR_DATA_0 = (v0); \
|
||||
reg_write(r);
|
||||
reg_write(r); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+16
-7
@@ -121,6 +121,7 @@ __xdata uint16_t management_vlan;
|
||||
__xdata uint8_t tx_seq;
|
||||
|
||||
__xdata uint8_t stpEnabled;
|
||||
__xdata uint8_t igmpEnabled;
|
||||
__xdata char hostname[24]; /* device hostname, default set at boot, see rtl837x_common.h */
|
||||
|
||||
__code uint16_t bit_mask[16] = {
|
||||
@@ -1152,7 +1153,7 @@ void handle_rx(void)
|
||||
print_string("STP TX\n");
|
||||
tcpip_output();
|
||||
}
|
||||
} else if (uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
|
||||
} else if (igmpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
|
||||
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x16) {
|
||||
igmp_packet_handler();
|
||||
if (uip_len) {
|
||||
@@ -2112,20 +2113,28 @@ void main(void)
|
||||
uip_ipaddr(&uip_hostaddr, ownIP[0], ownIP[1], ownIP[2], ownIP[3]);
|
||||
uip_ipaddr(&uip_draddr, gatewayIP[0], gatewayIP[1], gatewayIP[2], gatewayIP[3]);
|
||||
uip_ipaddr(&uip_netmask, netmask[0], netmask[1], netmask[2], netmask[3]);
|
||||
uip_ethaddr.addr[0] = 0xff;
|
||||
if (machine.mac_flash_offset) {
|
||||
flash_region.addr = machine.mac_flash_offset;
|
||||
flash_region.len = FLASH_BUF_SIZE;
|
||||
flash_read_bulk(flash_buf);
|
||||
// accept only a real unicast, globally-administered address (reject blank/LAA/multicast/all-zero OUI)
|
||||
if (flash_buf[0] != 0xff && !(flash_buf[0] & 0x03) && (flash_buf[0] | flash_buf[1] | flash_buf[2])) {
|
||||
uip_ethaddr.addr[0] = flash_buf[0]; uip_ethaddr.addr[1] = flash_buf[1];
|
||||
uip_ethaddr.addr[2] = flash_buf[2]; uip_ethaddr.addr[3] = flash_buf[3];
|
||||
uip_ethaddr.addr[4] = flash_buf[4]; uip_ethaddr.addr[5] = flash_buf[5];
|
||||
}
|
||||
}
|
||||
if (uip_ethaddr.addr[0] == 0xff) { // no valid flash MAC -> generate locally-administered
|
||||
reg_read_m(RTL837X_REG_CHIP_UUID);
|
||||
#ifdef DEBUG
|
||||
print_string("SoC UUID: "); print_sfr_data();
|
||||
#endif
|
||||
uip_ethaddr.addr[0] = 0x06; // LAA prefix
|
||||
uip_ethaddr.addr[3] = sfr_data[0] ^ sfr_data[3];
|
||||
uip_ethaddr.addr[4] = sfr_data[1] ^ sfr_data[3];
|
||||
uip_ethaddr.addr[5] = sfr_data[2] ^ sfr_data[3];
|
||||
reg_read_m(RTL837X_REG_CHIP_LOT_NO);
|
||||
#ifdef DEBUG
|
||||
print_string(", LOT: "); print_sfr_data(); write_char(' ');
|
||||
#endif
|
||||
uip_ethaddr.addr[1] = sfr_data[0] ^ sfr_data[2];
|
||||
uip_ethaddr.addr[2] = sfr_data[1] ^ sfr_data[3];
|
||||
}
|
||||
print_string("Setting MAC to: ");
|
||||
print_byte(uip_ethaddr.addr[0]); write_char(':'); print_byte(uip_ethaddr.addr[1]); write_char(':');
|
||||
print_byte(uip_ethaddr.addr[2]); write_char(':'); print_byte(uip_ethaddr.addr[3]); write_char(':');
|
||||
|
||||
+15
-1
@@ -106,9 +106,23 @@ typedef unsigned short uip_stats_t;
|
||||
/**
|
||||
* uIP buffer size.
|
||||
*
|
||||
* Sized to the largest frame the CPU port accepts on ingress: anything above
|
||||
* that the NIC drops in hardware, so a larger buffer only costs XDATA. Measured
|
||||
* with ICMP, which bypasses MSS and so probes the hardware directly: a 1502-byte
|
||||
* payload is answered and 1503 is not, which puts the frame at 1556 bytes of
|
||||
* uip_buf. The limit is the NIC's rather than a port's, so how the frame was
|
||||
* tagged on the wire does not change it.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_BUFFER_SIZE 2200
|
||||
#define UIP_CONF_BUFFER_SIZE 1556
|
||||
|
||||
/**
|
||||
* Bytes of the buffer kept out of the advertised MSS.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_BUFFER_EXTRA 30
|
||||
|
||||
/**
|
||||
* CPU byte order.
|
||||
|
||||
+13
-5
@@ -298,11 +298,8 @@
|
||||
|
||||
/**
|
||||
* The TCP maximum segment size.
|
||||
*
|
||||
* This is should not be to set to more than
|
||||
* UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
|
||||
*/
|
||||
#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
|
||||
#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - UIP_BUFFER_EXTRA)
|
||||
|
||||
/**
|
||||
* The size of the advertised receiver's window.
|
||||
@@ -381,6 +378,17 @@
|
||||
#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
|
||||
#endif /* UIP_CONF_BUFFER_SIZE */
|
||||
|
||||
/**
|
||||
* Bytes of uip_buf kept out of the advertised MSS.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#ifndef UIP_CONF_BUFFER_EXTRA
|
||||
#define UIP_BUFFER_EXTRA 0
|
||||
#else /* UIP_CONF_BUFFER_EXTRA */
|
||||
#define UIP_BUFFER_EXTRA UIP_CONF_BUFFER_EXTRA
|
||||
#endif /* UIP_CONF_BUFFER_EXTRA */
|
||||
|
||||
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||
|
||||
@@ -447,7 +455,7 @@ void uip_log(char *msg);
|
||||
#ifdef UIP_CONF_LLH_LEN
|
||||
#define UIP_LLH_LEN UIP_CONF_LLH_LEN
|
||||
#else /* UIP_CONF_LLH_LEN */
|
||||
#define UIP_LLH_LEN ETHER_HEADER_SIZE + RTL_FRAME_DESC_SIZE
|
||||
#define UIP_LLH_LEN (ETHER_HEADER_SIZE + RTL_FRAME_DESC_SIZE)
|
||||
#endif /* UIP_CONF_LLH_LEN */
|
||||
|
||||
/** @} */
|
||||
|
||||
Reference in new issue
Block a user