Skip to content

Dev/net layer v2#5

Open
NguyenDuongHoangHai wants to merge 73 commits into
Vinalinux-Org:mainfrom
NguyenDuongHoangHai:dev/net-layer-v2
Open

Dev/net layer v2#5
NguyenDuongHoangHai wants to merge 73 commits into
Vinalinux-Org:mainfrom
NguyenDuongHoangHai:dev/net-layer-v2

Conversation

@NguyenDuongHoangHai

Copy link
Copy Markdown

No description provided.

- Add CPSW peripheral region (0x4A100000, 1MB) to platform memmap
- Map CPSW in mmu_build_page_table_boot() so region accessible at boot
- Copy CPSW entry in mmu_new_pgd() for forked processes
- Move mdio_init() to after mmu_init() — MMU must be ready before MDIO access

Root cause: MDIO_CONTROL write at 0x4A101004 caused Translation fault (DFSR=0x805)
because CPSW bus was not mapped. Only L4_WKUP and L4_PER were previously mapped.
Bug 01: MDIO state machine never became IDLE because the CPSW 125MHz
functional clock domain was gated. Added CM_PER_CPSW_CLKSTCTRL wake-up
before CPGMAC0_CLKCTRL module enable per AM335x TRM Ch.08.
Bug 01 root cause: BootROM does not enable DPLL_CORE M5 divider output.
MDIO state machine requires this 125MHz functional clock to run.
- bootloader/clock.c: set CM_DIV_M5_DPLL_CORE = divider 8, gate forced on
- mdio.c: remove wrong CLKACT_125M poll, clean up DBG prints
…transaction

AM335x TRM: MDIO_CONTROL.IDLE sets after state machine processes a user
access frame, not during module enable. Polling it in init is wrong.
Sync is handled per-transaction by USERACCESS0.GO bit (mdio_wait_go).
CFLAGS += inside ifneq was overwritten by CFLAGS = below it.
Moved test detection block to after base CFLAGS is defined.
PHY ID constants use LAN8710A values (PHYSID1=0x0007, PHYSID2=0xC0F0).
Makefile TESTCASE_L1 block picks these up automatically at build time.
Implement cpsw.c/h: clock verify, MII pinmux, SS/CPDMA/MAC/ALE init,
single-BD TX/RX via CPPI_RAM polling model.

Design decisions:
- No MAC_LOOPBACK — real network traffic from boot
- mdio.c owns clock enable, cpsw.c only verifies CLKACTIVITY_CPSW_125M
- Polling RX via cpsw_rx_poll() from idle task, no INTC wiring needed
- Single TX+RX BD in CPPI_RAM (device memory) — no cache coherency issue
Merge 4 file gốc (ether.c + arp.c + ip.c + icmp.c) thành 1 file netcore.c.

- netcore.h: 7 public API + NETCORE_IP4() macro
- netcore.c: ~350 LOC, bottom-up order, không cần forward declaration
- arp_resolve() tự gọi cpsw_rx_poll() trong poll loop — nhận ARP Reply
  mà không cần idle_task (tránh deadlock khi scheduler chưa chạy)
- netcore_ping() pattern tương tự cho ICMP Echo wait
- Buffer sizes dẫn từ CPSW_FRAME_MAXLEN=1024: ETH=1010, IP=990, UDP=982
- Makefile: add netcore.o build rule
- main.c: netcore_init(NETCORE_IP4(192,168,1,100)) sau cpsw_init()
- idle.c: cpsw_rx_poll() sau WFI cho UDP RX background polling
Vấn đề:
  CPDMA bị kẹt ở RX_HOST_ERR (DMASTATUS=0x2000, error code 1:
  'SOP buffer ownership bit not set') ngay sau khi enable RX_CONTROL.
  CPDMA đọc BD qua L3/L4 interconnect trước khi CPU write propagate
  xong đến CPPI_RAM, thấy OWNER=0 và halt channel vĩnh viễn.

Root cause (xác nhận qua diagnostic):
  - BD content đúng: BUFPTR=0x4a102420, FLAGS=0x8c000400 (OWNER=1)
  - Error xuất hiện NGAY khi enable RX_CONTROL, không cần frame đến
  - Cache fix (DSB/DMB + invalidate) không có tác dụng vì CPPI_RAM
    là device memory, không phải DDR
  - TRM §14.3.1.4: CPDMA halt channel cho đến khi software recover

Fix:
  Thêm cpsw_rx_recover() được gọi tự động từ cpsw_rx_poll() khi
  detect DMASTATUS bit 13 (RX_HOST_ERR):
    1. Disable RX/TX channel
    2. Soft reset CPDMA (clear error state machine)
    3. Re-clear tất cả HDP/CP registers
    4. Re-apply CPDMA config (buffer offset, interrupt mask, WR pacing)
    5. Re-enable TX
    6. Re-arm RX BD (OWNER=1, BUFPTR, BUFLEN đúng)
    7. Kick HDP → enable RX_CONTROL (đúng thứ tự)

Isolation:
  cpsw_rx_recover() CHỈ đụng đến CPDMA (0x4A100800).
  Không đụng đến:
    - PHY layer (mdio.c): MDIO/PHY registers độc lập
    - MAC sliver (SL1_MACCONTROL): MAC tiếp tục chạy
    - ALE: bypass mode và port forward được giữ nguyên
  TX bị pause ngắn (~microseconds) trong khi reset.

Safety:
  Giới hạn 3 lần recover để tránh infinite loop nếu hardware lỗi.
  recover_count reset về 0 khi DMASTATUS clean.

Files thay đổi:
  cpsw.c:
    - Thêm CPDMA_DMASTATUS register define + DMASTATUS_RX_HOST_ERR bit
    - Thêm static cpsw_rx_recover()
    - cpsw_rx_poll(): check DMASTATUS trước khi check BD_FLAGS
  irqs.h:
    - Thêm PLATFORM_IRQ_CPSW_RX/TX/MISC (IRQ 40-43, TRM Table 6-1)
      để chuẩn bị cho interrupt-driven RX nếu cần sau này

Tested: RXGOODFRAMES tăng 149→216 xác nhận MAC nhận frame.
        Sau fix, CPDMA sẽ recover và deliver frame lên CPU.

Ref: AM335x TRM §14.3.1.4 (CPDMA Error Recovery)
     Document_for_training/05_fix_strategy_analysis.md
- DMASTATUS=0x2000 (RX_HOST_ERR): CPDMA đọc BD trước khi CPU write
  propagate xong qua L3/L4 interconnect, thấy OWNER=0, halt channel
  mãi mãi không tự recover
- netcore.c gọi scheduler_get_tick() nhưng function chưa được implement
  → linker error: undefined reference to scheduler_get_tick
- Bỏ giới hạn recover_count < 3: CPDMA recover vô hạn khi bị error
- Thêm delay 500000 cycles sau HDP kick trước khi enable RX_CONTROL
  để write propagate qua L3/L4 interconnect đến CPPI_RAM
Thay polling + recovery loop bằng interrupt-driven RX:
- ISR (IRQ 41): disable pacing → write EOI ngay → set flag
- cpsw_rx_poll(): chỉ xử lý khi ISR set flag
- Thêm cpsw_rx_irq_enable() gọi sau irq_init() trong main.c

EOI write trong ISR là điểm mấu chốt: CPDMA nhận EOI ngay
lập tức, không bị stuck RX_HOST_ERR như polling mode.
CPDMA_RX_CONTROL giờ được enable trong cpsw_rx_irq_enable()
thay vì cpsw_bd_init(), đảm bảo:
1. BD write đã propagate qua L3/L4 đến CPPI_RAM
2. ISR đã được register trước khi frame đến
3. EOI được write ngay trong ISR → CPDMA không bị stuck
IRQ 41 phải được enable SAU khi CPU sẵn sàng nhận interrupt.
Nếu enable trước irq_enable(), frame đến trong boot sẽ fire IRQ
nhưng CPU không nhận → CPDMA không nhận EOI → stuck.
- ISR: log 'ISR fired!' để verify interrupt được nhận
- cpsw_rx_irq_init(): log CPDMA_RX_CONTROL trước/sau enable
- Log CPSW_WR_C0_RX_EN, RX0_HDP, BD_FLAGS để verify state
State đúng: RX_CONTROL=1, WR_RX_EN=1, HDP=0x4a102010, BD_FLAGS=0x8c000400
Nhưng ISR chưa bao giờ fired → IRQ 41 không được dispatch.

Fallback: cpsw_rx_poll() check BD_FLAGS trực tiếp nếu s_rx_pending=0.
Nếu frame đến mà ISR không fired → log warning + xử lý frame.
Giúp xác định IRQ routing có vấn đề hay không.
Thay vì chỉ re-arm BD, thực hiện full reset CPDMA trước khi enable RX:
1. Disable RX/TX
2. Soft reset CPDMA (clear error state)
3. Clear tất cả HDP/CP
4. Re-arm BD fresh
5. Kick HDP
6. Enable interrupt + RX_CONTROL
7. Log DMASTATUS ngay sau enable

Expected: DMASTATUS=0x80000000 sau enable, ISR fired khi ping
BD đúng (HDP=0x4a102010, FLAGS=0x8c000400) nhưng DMASTATUS=0x2000
ngay sau enable. Root cause: MAC đang nhận frame trong khi CPDMA
đang được reset/re-init → frame đến trước khi CPDMA sẵn sàng.

Fix: clear GMII_EN trước khi reset CPDMA, re-enable sau khi
CPDMA đã sẵn sàng hoàn toàn.
TRM §14.3.1.4: DMASTATUS error bits KHÔNG bị clear bởi soft reset.
Phải write 1 vào bits [16:13] để clear RX_HOST_ERR.

DMASTATUS=0x2000 là error từ lần boot trước còn tồn tại trong
hardware register. Clear bằng write 0x0001E000 trước enable RX.
netcore.c:
  - g_icmp_rx_count, g_icmp_tx_count: đếm ICMP request/reply
  - netcore_cksum(): expose net_cksum() cho unit test
  - netcore_build_arp_request(): build ARP request vào buffer
  - netcore_build_icmp_reply(): build ICMP reply từ request
  - netcore_arp_resolve(): expose arp_resolve() cho test
  - netcore_get_icmp_rx/tx_count(): đọc counters

testcase/layer2/cpsw_test.c:
  T1: CPSW clock active
  T2: SS soft reset
  T3: CPDMA reset + DMASTATUS clean
  T4: MAC internal loopback (CPDMA TX→RX verify)
  T5: RX stats counter

testcase/layer3/netcore_test.c:
  T1: IP checksum correctness (unit test)
  T2: ARP packet build (unit test)
  T3: ICMP echo reply build (unit test)
  T4: ARP reply từ laptop
  T5: Ping reply to laptop (DoD Layer 3)
Tách netcore.c (ether+arp+ip+icmp merged) thành từng file riêng.
Bước đầu: chỉ giữ Ethernet frame layer.

ether.c / ether.h:
  - ether_init(): setup MAC, register CPDMA callback
  - ether_tx(): build Ethernet header + cpsw_tx()
  - ether_rx(): strip header + dispatch theo EtherType
  - ether_set_ipv4_handler() / ether_set_arp_handler()
  - Không biết gì về ARP, IP, ICMP

main.c: thay netcore_init() bằng ether_init()
idle.c: cập nhật comment

ARP, IP, ICMP sẽ được thêm sau khi Ethernet layer hoạt động.
Gửi 1 frame broadcast EtherType=0x9000 ngay sau init.
Log: [ETH] smoke test tx: OK/FAIL
Wireshark filter: eth.type == 0x9000
Nếu thấy frame trên Wireshark → ether_tx() + CPDMA + MAC + PHY OK.
- ether_test_arp_rx(): log khi nhận ARP frame từ laptop
- ether_test_ipv4_rx(): log khi nhận IPv4 frame từ laptop
- Đăng ký qua ether_set_arp_handler() / ether_set_ipv4_handler()

Test: ping từ laptop → [ETH-TEST] RX IPv4 frame
      arp từ laptop → [ETH-TEST] RX ARP frame
Nếu thấy log → ether_rx() dispatch hoạt động đúng
- ISR: bỏ 'ISR fired!' log — ISR phải ngắn, không blocking
- fallback poll: bỏ WARN log RX_HOST_ERR và 'frame without ISR'
- Giữ silent drop thay vì spam UART
Bug: BD_OWNER=bit31, BD_SOP=bit27, BD_EOP=bit26 (SAI)
Fix: BD_SOP=bit31, BD_EOP=bit30, BD_OWNER=bit29, BD_EOQ=bit28

Verified từ Linux davinci_cpdma.c:
  CPDMA_DESC_SOP   = BIT(31)
  CPDMA_DESC_EOP   = BIT(30)
  CPDMA_DESC_OWNER = BIT(29)
  CPDMA_DESC_EOQ   = BIT(28)

CPDMA đọc OWNER tại bit29. VinixOS set bit31=1 (SOP) nhưng
bit29=0 → CPDMA thấy OWNER=0 → báo 'Ownership bit not set'
→ DMASTATUS=0x2000 → halt channel → không nhận được frame.
Thêm section APPENDIX với C macro definitions cho 7 register nhóm:
A.1 BD Word 3 flags (SOP/EOP/OWNER/EOQ bit positions)
A.2 MACCONTROL (GMII_EN phải write cuối cùng)
A.3 ALE_CONTROL (ENABLE/BYPASS/PORT_FORWARD)
A.4 GMII_SEL (MII/RMII/RGMII mode selection)
A.5 CPDMA_EOI_VECTOR (RX=1, TX=2, MISC=3)
A.6 CPSW_WR interrupt pacing
A.7 STATERAM HDP/CP + CPPI_RAM layout

Mục đích: AI có thể tra cứu bit positions chính xác
thay vì suy đoán từ text description.
- Add ARP packet structure and cache management
- Implement ARP request/reply handling
- Add NetCore wrapper for unified interface
- Initialize ARP in main.c with proper handlers
- Update Makefile to build ARP components
- Set BBB IP to 192.168.10.100 for testing

This enables network layer functionality after Ethernet.
…vent packet loss

- Remove CPSW_WR_C0_RX_EN disable in cpsw_rx_isr() - was causing packet loss
- Remove RX disable in fallback path of cpsw_rx_poll()
- Remove unnecessary RX re-enable after frame processing
- Follow Linux CPSW driver pattern - keep RX enabled, use EOI only
- This should fix BBB not receiving ARP requests from laptop
…e packets

- Change CPDMA_RX_INTMASK_SET to CPDMA_RX_INTMASK_CLEAR (0x1u)
- RX interrupts were being masked, preventing ISR from being called
- This should enable packet reception and fix ARP communication
- Expected result: [CPSW] RX: ISR signaled frame ready should appear in logs
- Add INTC_MIR0, INTC_MIR1, and INTC_SIR_IRQ register debugging
- Check if IRQ 41 is properly unmasked in interrupt controller
- Verify interrupt controller recognizes CPSW RX interrupt
- This will help identify if issue is at hardware level
…nable_irq

- Add debug logging to verify intc_enable_irq actually works
- Log MIR register before/after to confirm IRQ unmasking
- Root cause: IRQ 41 not being unmasked (MIR0 stays 0xffffffff)
- Expected: MIR0 should change to 0xfffffffb (bit 9 cleared)
- This should finally allow CPSW RX interrupts to trigger
- errno.h: add kernel-side error codes (EIO/EAGAIN/ENOMEM/EINVAL)
- arp: spinlock on cache, wait_event/wake_up in resolve, tick-based
  60s expiry, remove busy-wait polling, return -EAGAIN on timeout
- ipv4: rename log prefix [IPV4]->[IP], replace 65KB stack buf with
  ETH_MAX_PAYLOAD bound, add fragmentation hard-drop, verify RX
  checksum, atomic_t counters, remove extern decl in function body
- icmp: fix type constants per RFC 792 (DEST_UNREACH=3/SOURCE_QUENCH=4
  /REDIRECT=5), replace VLA with kmalloc/kfree, verify RX checksum,
  atomic_t counters, proper errno returns
- intc.c: move #include uart.h to top — was included after first use
  of uart_printf at line 53, causing implicit declaration + conflicting
  types warnings
- main.c: add #include mdio_test.h inside ENABLE_LAYER1_TEST guard —
  mdio_layer1_test() was called undeclared
- netcore.c: add #include cpsw.h — cpsw_get_mac() was called undeclared
- ipv4.c: remove leftover dst_ip unused variable, fix checksum unaligned
  ptr cast (already in [1] but re-staged for clean log)
- icmp.c: add #include ether.h for ETH_MAX_PAYLOAD, fix checksum
  unaligned ptr cast (already in [1] but re-staged for clean log)
- netcore.c: replace cpsw_get_mac() with ether_get_mac() — netcore
  must not bypass ether layer to call CPSW driver directly
- netcore.c: remove #include cpsw.h (added by mistake in [2])
- netcore.c: fix error return -1 -> -EINVAL in build_arp_request
- netcore.c: use ETH_HEADER_LEN/ETH_ADDR_LEN/ETHERTYPE_ARP constants
  instead of magic numbers (14, 6, 0x08/0x06)
- netcore.c: log prefix [NETCORE] -> [NET] per handoff spec
- netcore.h: clean up comments, mark build_arp_request as test-only
…ations

- Add icmp_dest_unreachable() body in icmp.c (RFC 792 format)
- Add missing arp.h/ipv4.h/icmp.h includes in network_test_runner.c"

yes
git add kernel/src/drivers/icmp.c testcase/layer3/network_test_runner.c
git commit -m "$(cat <<'EOF'
Fix(net): [4] implement icmp_dest_unreachable and fix implicit declarations

- Add icmp_dest_unreachable() body in icmp.c (RFC 792 format)
- Add missing arp.h/ipv4.h/icmp.h includes in network_test_runner.c
…ap32

Outgoing ARP packets had IPs in host byte order (little-endian ARM).
Laptop saw wrong IPs (e.g. 80.10.168.192 instead of 192.168.10.80)
and never replied -> wait_event blocked forever.

Fix: bswap32 sender_ip and target_ip in arp_send_request/arp_send_reply,
and same correction in netcore_build_arp_request.
… ISR

- main.c: move irq_enable()+cpsw_rx_irq_enable() before network tests
  so wait_event in arp_resolve can receive replies via ISR
- cpsw.c: process RX frame inline in cpsw_rx_isr instead of deferring
  to cpsw_rx_poll; idle task not running (scheduler_start commented out)
  so deferred processing never happened
- Replace CPDMA_RX_INTMASK_CLEAR with CPDMA_RX_INTMASK_SET (0x0A8):
  CLEAR (0x0AC) disables interrupt; SET (0x0A8) enables it.
  Previous code disabled channel 0 RX interrupt — ISR never fired.

- Register ISR + enable INTC IRQ BEFORE enabling CPDMA_RX_CONTROL
  and MAC GMII_EN. Eliminates race where a frame could arrive before
  the ISR was ready, consuming the BD with no re-arm.
Copy RX frame to static buffer, then re-arm BD immediately before
calling ether_rx callback. Previously BD stayed OWNER=0 for ~50ms
during callback (uart_printf storm), causing CPDMA to silently drop
any frame arriving in that window — root cause of 75% ping loss.

Also remove ISR debug printf (rx_isr_count) confirmed working v3.
…use IRQ 41 (CPSW RX) never fires — causing the test to hang after the first who-has message
…ị tắt (ALE_CONTROL = 0), frame đến được MAC nhưng bị ALE chặn, không bao giờ xuống CPDMA. MACINVECTOR = 0 xác nhận điều này — MAC chưa bao giờ báo có frame
…ị tắt (ALE_CONTROL = 0), frame đến được MAC nhưng bị ALE chặn, không bao giờ xuống CPDMA. MACINVECTOR = 0 xác nhận điều này — MAC chưa bao giờ báo có frame
AM335x TRM Table 14-61: ALE_IDVER=0x000, ALE_CONTROL=0x008.
Offset 0x004 là vùng reserved — mọi write no-op, read trả về 0.
ALE chưa bao giờ được enable từ đầu dự án, toàn bộ RX frame bị
ALE drop trước khi vào CPDMA. MACINVECTOR = 0 xuyên suốt log.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant