mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
a0628c7df5b1ef856402f6c2c83ea7ad48cf07b5
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a0628c7df5 |
sfp: read the EEPROM in blocks instead of a byte at a time
The I2C controller transfers up to sixteen bytes per transaction and page_impl.c already used that for sfp_send_data(), while sfp_read_reg() asked for one byte and every caller looped. Reading a module therefore cost one address phase per byte: 87 transactions when a module is inserted, 52 for the sfp command, 36 for the vendor block in status.json. sfp_read_block() replaces sfp_read_reg() and the callers that already wanted a run of registers ask for it once: the vendor fields as three 16 byte pages, the diagnostics as one transfer, rate and encoding together. That drops the three paths above to 8, 6 and 3 transactions, and sfp_send_data() loses its copy of the transfer. The vendor loops now run over 16..63 rather than 20..59 so the page base is a multiple of sixteen and the index into the buffer is a single AND. The four extra bytes at each end are read and discarded. The diagnostics read asks for 16 bytes rather than the 15 it uses, because 16 is a width the shipped firmware already exercises and 15 is not. The device address, the bus selection and the start bit go into the control register in one write now that the memory address is written first, so a transfer touches that register once instead of three times. The register reads take their result from the SFRs directly rather than through the sfr_data mirror. The result is a bool and the destination is sfp_buf, so a caller that cares about a failed transfer looks at the return value instead of a flag. Every caller gives up on the first failed read rather than carrying a flag to the end, which is why the module read moved out of handle_sfp into a function of its own. A module whose read fails is left marked as absent, so the next poll retries it instead of configuring the SerDes from bytes that never arrived. BANK1 -194 bytes, BANK2 +382, common segment +44, xdata +15 for the buffer, and one byte more of internal RAM free than before the series. Built for all 25 machine definitions on sdcc 4.5.0; the tightest common segment is 98 bytes free on SWTG024AS_V2_0, against 54 before this series. |
||
|
|
9a96c80af2 |
sfp: move the I2C transfer to the banked pins module
sfp_read_reg() sat in rtlplayground.c, so it occupied the common 16 KB window that every bank shares, even though nothing outside the SFP paths calls it. That window is the tightest resource in the image: SWTG024AS_V2_0 and SWTG024AS_A_2_0_1_5C_1SFP had 54 bytes left in it. rtl837x_pins.c is already in BANK2 and already holds the I2C bus helpers this function calls, so the transfer belongs there. The function moves verbatim and becomes __banked; the prototype in rtl837x_common.h says so, which is what keeps the callers in BANK1 and BANK2 honest. No behaviour change. The common segment gains 200 bytes on every machine: 159 to 359 free on SWTGW218AS, 54 to 254 on the two variants above. BANK1 +6 bytes, BANK2 +336. Built on sdcc 4.5.0. |
||
|
|
1d1e33f4d5 |
sfp: notice when an I2C read fails
sfp_read_reg() waited for the transfer to finish and then read the output register whatever the outcome, so an address nothing acknowledged came back as an ordinary byte and no caller could tell it apart from data. The vendor SDK looks at bit 1 of the control register for exactly this, and we did not. A failure now sets sfp_i2c_fail and the read returns 0xff, which is already the value sfp_apply_quirks() reads as either a failed transfer or a voltage the spec does not allow, so that test starts being true when it should be. The insertion path and the sfp command clear the flag first and say so afterwards, rather than presenting the bytes as though they came from the module. What this deliberately does not do is act on the failure. Skipping sds_config() when the rate read failed is the obvious next step, but a module that raises the bit spuriously would then never be configured at all, which is worse than what happens today, and I have no way to judge how often the bit is right. That decision belongs with someone holding the board. It also leaves the other half of the rewrite alone, reading and writing up to sixteen bytes per transaction. doc/sfp.md describes only the single byte path and does not name a length field, and guessing at a register I cannot test is how the last attempt at this function went wrong. 40 bytes of the common segment, 51 of BANK2 and 1 of xdata, nothing in BANK1 or internal RAM. Built for SWTGW218AS and KP_9000_6XHML_X2 on sdcc 4.5.0. Not tested on hardware: shorting the clock line, as in #342, should now print the failure line instead of a plausible looking byte. |
||
|
|
59c60504e7 |
crtbank: put the bank switching helpers in HOME
__sdcc_banked_call and __sdcc_banked_ret were assembled into GSFINAL, which sits in the startup path: GSINIT ends exactly where GSFINAL begins, so the processor falls into it rather than being sent there. It works today only because this object comes after every C object on the link line, so the LJMP to __sdcc_program_startup is laid down first and the helpers land behind it. Reordering that line, or moving main() into another module, would put the helper body at the fallthrough address instead, and the board would not come up out of a build that reports nothing wrong. SDCC's own crtbank.asm declares the area order and then puts both symbols in HOME, so the file takes that name and that preamble as well. GSFINAL now holds the three byte jump and nothing else. Of 401 symbols 17 change address, every one in the startup region, and between the reset vector and 0x0094 not a byte differs, so no interrupt vector is disturbed. Run on a SWTGW218AS: it came back after about 42 seconds reporting the new build, with its stored configuration byte identical and every link at the speed it had before. |
||
|
|
f2c6ac01d9 |
port: read a trunk's members through one function
The member mask of an aggregation group is decoded by hand in two places, the lag command and the JSON behind the aggregation page, and every branch that touches trunks adds another copy. port_lag_members_get() sits next to port_lag_members_set() and both readers call it. It answers from the hardware, so it covers a group configured with lag and one a protocol brought up, without either having to say so. It reads through reg_read() rather than reg_read_m(), so sfr_data is left alone. Neither caller looked at it afterwards; both read the hash register next. |
||
|
|
4ff009dbfc |
uip: cap TCP MSS to 1460 to survive jumbo-MTU clients (#298)
* uip: parenthesise UIP_LLH_LEN The macro expands to a bare sum, so wherever it is subtracted the second term gets added instead. UIP_TCP_MSS - and with it UIP_RECEIVE_WINDOW - therefore comes out 24 bytes above the buffer's real capacity. UIP_APPDATA_SIZE and UIP_REASS_BUFSIZE are wrong the same way, though neither is reachable today. The additions, uip_buf[UIP_LLH_LEN] and friends, were right by luck. * uip: keep the advertised MSS below the buffer edge Deriving the MSS straight from the buffer size makes the switch advertise exactly the segment that fills uip_buf to its last byte, and a peer that takes it literally corrupts every large upload: the firmware image arrives fully acknowledged, with no retransmissions on the wire, yet the CRC over the streamed body never matches and the flash write is abandoned. Isolated by changing nothing but the segment size, same buffer and same file: 1490-byte segments fail four times out of four, 1460-byte segments succeed, 745-byte segments succeed. Linux halves its segments against a window this small, so only macOS on a jumbo link ever produces a full-size segment - which is why the failure hides so well. Where exactly the full segment breaks the stream is not pinned down yet; until it is, the advertised MSS stays a step below the edge. * uip: size the buffer to the largest frame the CPU port accepts UIP_TCP_MSS derives from UIP_CONF_BUFFER_SIZE, and the buffer was large enough for frames the hardware will never deliver, so the switch advertised a segment size no peer could usefully reach. A client on a jumbo-MTU link took it at its word and the oversized replies went nowhere. Size the buffer to the ingress limit instead. ICMP bypasses MSS and so probes the hardware directly: on a SWTGW218AS a 1502-byte payload is answered and 1503 never arrives, which puts the largest frame the NIC hands us at 1556 bytes of uip_buf. UIP_TCP_MSS then derives to 1490, the same edge measured over TCP. Frames above the limit are dropped by the NIC rather than written to the buffer - an 8 kB ping leaves the switch untouched - so nothing overruns it. Frees 644 bytes of XDATA. * uip: trim these comments, one of which had stopped being true The note above UIP_CONF_BUFFER_SIZE claimed the MSS derives from it as 1490. It does not: the commit that follows pins the MSS at 1460 on purpose, a step below that ceiling, because a segment filling the buffer to its last byte corrupts large uploads. Left as it was, the file argued with itself. Both blocks are shorter now. What justifies the numbers stays, which is the ICMP measurement behind 1556 and the four-out-of-four failure behind 1460. What went is the storytelling around them, which belongs in this thread rather than in a config header. * uip: derive the MSS from the buffer again, minus explicit headroom The review asked why the buffer size and the MSS are both set by hand when one used to follow from the other. They answer different questions, but the gap between them is a number in its own right, so it gets a name now: UIP_CONF_BUFFER_EXTRA, and UIP_TCP_MSS goes back to being derived. The headroom is where the measurement lives. A segment that fills uip_buf to its last byte corrupts large uploads: with nothing but the segment size changing, 1490 fails four times out of four and 1460 succeeds. With the buffer sized to the frame the NIC accepts, an extra of 30 lands on 1460. Deriving it the other way round does not work. Sizing the buffer from a 1460 byte MSS gives 1526, which is 30 bytes under the frame the NIC actually delivers. A 1502 byte ICMP payload occupies 1556 bytes of uip_buf and is answered today, and it would stop fitting. The generated image is byte for byte the same as the one with 1460 written out, so the expression lands on the value that was measured. --------- Co-authored-by: d00f <tokyusho@chatik.pl> |