Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Milk-V Mars CM #22

Open
geerlingguy opened this issue Oct 27, 2023 · 61 comments
Open

Milk-V Mars CM #22

geerlingguy opened this issue Oct 27, 2023 · 61 comments

Comments

@geerlingguy
Copy link
Owner

geerlingguy commented Oct 27, 2023

DSC04058

Basic information

  • Board URL (official): https://milkv.io/mars-cm
  • Board purchased from: ARACE
  • Board purchase date: 2023-09-05
  • Board specs (as tested): 4 GB RAM / 16 GB eMMC
  • Board price (as tested): $54 (+$12 shipping)

Linux/system information

# output of `neofetch`
       _,met$$$$$gg.          root@starfive 
    ,g$$$$$$$$$$$$$$$P.       ------------- 
  ,g$$P"     """Y$$.".        OS: Debian GNU/Linux bookworm/sid riscv64 
 ,$$P'              `$$$.     Host: Milk-V Mars CM eMMC 
',$$P       ,ggs.     `$$b:   Kernel: 5.15.0 
`d$$'     ,$P"'   .    $$$    Uptime: 30 mins 
 $$P      d$'     ,    $$P    Packages: 1324 (dpkg) 
 $$:      $$.   -    ,d$$'    Shell: bash 5.2.2 
 $$;      Y$b._   _,d$P'      Terminal: /dev/pts/0 
 Y$$.    `.`"Y$$$$P"'         CPU: (4) @ 1.500GHz 
 `$$b      "-.__              Memory: 426MiB / 3874MiB 
root@starfive:~# 
   `Y$$.
     `$$b.
       `Y$$b.
          `"Y$b._
              `"""

# output of `uname -a`
Linux starfive 5.15.0 #9 SMP Sun Oct 8 17:14:43 CST 2023 riscv64 GNU/Linux

Benchmark results

CPU

Power

  • Idle power draw (at wall): 1.1 W
  • Maximum simulated power draw (stress-ng --matrix 0): 3.8 W
  • During Geekbench multicore benchmark: 3.1 W
  • During top500 HPL benchmark: 3.6 W

Disk

Built-in 16 GB eMMC Module

Benchmark Result
fio 1M sequential read 45.3 MB/s
iozone 1M random read 37.70 MB/s
iozone 1M random write 26.12 MB/s
iozone 4K random read 14.39 MB/s
iozone 4K random write 14.30 MB/s

2TB Kioxia XG8 NVMe SSD (via PCIe Gen 2 x1 interface)

Benchmark Result
fio 1M sequential read 151.00 MB/s
iozone 1M random read 242.58 MB/s
iozone 1M random write 248.08 MB/s
iozone 4K random read 38.09 MB/s
iozone 4K random write 88.16 MB/s

curl https://raw.githubusercontent.com/geerlingguy/pi-cluster/master/benchmarks/disk-benchmark.sh | sudo bash

Run benchmark on any attached storage device (e.g. eMMC, microSD, NVMe, SATA) and add results under an additional heading. Download the script with curl -o disk-benchmark.sh [URL_HERE] and run sudo DEVICE_UNDER_TEST=/dev/sda DEVICE_MOUNT_PATH=/mnt/sda1 ./disk-benchmark.sh (assuming the device is sda).

Also consider running PiBenchmarks.com script.

Network

iperf3 results:

1 Gbps Ethernet (built-in)

  • iperf3 -c $SERVER_IP: 920 Mbps
  • iperf3 --reverse -c $SERVER_IP: 879 Mbps
  • iperf3 --bidir -c $SERVER_IP: 941 Mbps up, 258 Mbps down

WiFi (built-in)

  • iperf3 -c $SERVER_IP: TODO Mbps
  • iperf3 --reverse -c $SERVER_IP: TODO Mbps
  • iperf3 --bidir -c $SERVER_IP: TODO Mbps up, TODO Mbps down

GPU

  • TODO: Haven't determined standardized benchmark yet. See Issue #2.

Memory

tinymembench results:

Click to expand memory benchmark result
tinymembench v0.4.10 (simple benchmark for memory throughput and latency)

==========================================================================
== Memory bandwidth tests                                               ==
==                                                                      ==
== Note 1: 1MB = 1000000 bytes                                          ==
== Note 2: Results for 'copy' tests show how many bytes can be          ==
==         copied per second (adding together read and writen           ==
==         bytes would have provided twice higher numbers)              ==
== Note 3: 2-pass copy means that we are using a small temporary buffer ==
==         to first fetch data into it, and only then write it to the   ==
==         destination (source -> L1 cache, L1 cache -> destination)    ==
== Note 4: If sample standard deviation exceeds 0.1%, it is shown in    ==
==         brackets                                                     ==
==========================================================================

 C copy backwards                                     :    993.0 MB/s (0.7%)
 C copy backwards (32 byte blocks)                    :    991.7 MB/s
 C copy backwards (64 byte blocks)                    :    991.7 MB/s
 C copy                                               :   1002.3 MB/s
 C copy prefetched (32 bytes step)                    :   1001.8 MB/s (0.4%)
 C copy prefetched (64 bytes step)                    :   1003.6 MB/s (0.4%)
 C 2-pass copy                                        :    829.9 MB/s
 C 2-pass copy prefetched (32 bytes step)             :    833.9 MB/s
 C 2-pass copy prefetched (64 bytes step)             :    832.6 MB/s (0.1%)
 C fill                                               :    868.7 MB/s (0.2%)
 C fill (shuffle within 16 byte blocks)               :    864.9 MB/s
 C fill (shuffle within 32 byte blocks)               :    868.8 MB/s (0.3%)
 C fill (shuffle within 64 byte blocks)               :    876.2 MB/s (0.4%)
 ---
 standard memcpy                                      :   1004.5 MB/s
 standard memset                                      :    884.3 MB/s (0.6%)

==========================================================================
== Memory latency test                                                  ==
==                                                                      ==
== Average time is measured for random memory accesses in the buffers   ==
== of different sizes. The larger is the buffer, the more significant   ==
== are relative contributions of TLB, L1/L2 cache misses and SDRAM      ==
== accesses. For extremely large buffer sizes we are expecting to see   ==
== page table walk with several requests to SDRAM for almost every      ==
== memory access (though 64MiB is not nearly large enough to experience ==
== this effect to its fullest).                                         ==
==                                                                      ==
== Note 1: All the numbers are representing extra time, which needs to  ==
==         be added to L1 cache latency. The cycle timings for L1 cache ==
==         latency can be usually found in the processor documentation. ==
== Note 2: Dual random read means that we are simultaneously performing ==
==         two independent memory accesses at a time. In the case if    ==
==         the memory subsystem can't handle multiple outstanding       ==
==         requests, dual random read has the same timings as two       ==
==         single reads performed one after another.                    ==
==========================================================================

block size : single random read / dual random read
      1024 :    0.0 ns          /     0.0 ns 
      2048 :    0.0 ns          /     0.0 ns 
      4096 :    0.0 ns          /     0.0 ns 
      8192 :    0.0 ns          /     0.0 ns 
     16384 :    0.0 ns          /     0.0 ns 
     32768 :    0.0 ns          /     0.0 ns 
     65536 :    5.4 ns          /    10.5 ns 
    131072 :    8.1 ns          /    15.8 ns 
    262144 :    9.5 ns          /    18.6 ns 
    524288 :   15.4 ns          /    28.6 ns 
   1048576 :   16.0 ns          /    30.6 ns 
   2097152 :   21.9 ns          /    38.5 ns 
   4194304 :   84.8 ns          /   166.5 ns 
   8388608 :  122.4 ns          /   242.6 ns 
  16777216 :  143.7 ns          /   285.6 ns 
  33554432 :  157.2 ns          /   313.1 ns 
  67108864 :  167.7 ns          /   334.6 ns 

Phoronix Test Suite

Results from pi-general-benchmark.sh:

  • pts/encode-mp3: TODO sec
  • pts/x264 4K: TODO fps
  • pts/x264 1080p: TODO fps
  • pts/phpbench: TODO
  • pts/build-linux-kernel (defconfig): TODO sec

sbc-bench results

Device / details Clockspeed Kernel Distro 7-zip multi 7-zip single AES memcpy memset kH/s
Milk-V Mars CM (JH7110) 1500 MHz 5.15 Bookworm riscv64 4110 1195 25070 930 830 -
@geerlingguy
Copy link
Owner Author

Just plopped this board on my Compute Module 4 IO Board, and it seems to do some sort of boot process, arriving at a flashing green LED (two flashes, then 1 second break, repeating).

The network LEDs light up too, but I don't see a new device on the network. No HDMI output, and I'm not 100% sure if the GPIO pinout is the same as Pi CM4, so I don't want to plug in UART yet...

I tried accessing the 'Get Started' docs page listed on the side of the box (http://milkv.io/docs/mars-cm), but that page is currently giving a 404 Page Not Found.

I've opened up an issue on the MilkV Community Forum: Mars CM - Getting Started guide missing?.

It would be great if this JH7110-based board could run as a drop-in replacement of the Compute Module 4... we'll see!

@geerlingguy
Copy link
Owner Author

Attaching to UART using the same pins as Mars (see Serial Console docs), I was able to monitor boot output...

U-Boot SPL 2021.10 (Oct 08 2023 - 17:13:43 +0800)
LPDDR4: 4G version: g8ad50857.
Trying to boot from SPI

OpenSBI v1.2
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|___./_____|
        | |
        |_|

Platform Name             : StarFive VisionFive V2
Platform Features         : medeleg
Platform HART Count       : 5
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 4000000Hz
Platform Console Device   : uart8250
Platform HSM Device       : ---
Platform PMU Device       : ---
Platform Reboot Device    : pm-reset
Platform Shutdown Device  : pm-reset
Platform Suspend Device   : ---
Firmware Base             : 0x40000000
Firmware Size             : 392 KB
Firmware RW Offset        : 0x40000
Runtime SBI Version       : 1.0

Domain0 Name              : root
Domain0 Boot HART         : 1
Domain0 HARTs             : 0*,1*,2*,3*,4*
Domain0 Region00          : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain0 Region01          : 0x0000000040000000-0x000000004003ffff M: (R,X) S/U: ()
Domain0 Region02          : 0x0000000040040000-0x000000004007ffff M: (R,W) S/U: ()
Domain0 Region03          : 0x0000000000000000-0xffffffffffffffff M: (R,W,X) S/U: (R,W,X)
Domain0 Next Address      : 0x0000000040200000
Domain0 Next Arg1         : 0x0000000042200000
Domain0 Next Mode         : S-mode
Domain0 SysReset          : yes
Domain0 SysSuspend        : yes

Boot HART ID              : 1
Boot HART Domain          : root
Boot HART Priv Version    : v1.11
Boot HART Base ISA        : rv64imafdcbx
Boot HART ISA Extensions  : none
Boot HART PMP Count       : 8
Boot HART PMP Granularity : 4096
Boot HART PMP Address Bits: 34
Boot HART MHPM Count      : 2
Boot HART MIDELEG         : 0x0000000000000222
Boot HART MEDELEG         : 0x000000000000b109


U-Boot 2021.10 (Oct 08 2023 - 17:13:43 +0800)

CPU:   rv64imacu_zba_zbb
Model: StarFive VisionFive V2
DRAM:  4 GiB
cdns3_bind: unsupported dr_mode
MMC:   sdio0@16010000: 0, sdio1@16020000: 1
Loading Environment from SPIFlash... SF: Detected gd25lq128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
*** Warning - bad CRC, using default environment

StarFive EEPROM format v2
...

It looks like it does automatically boot into Debian, and it says an eth0 link is up... (this is with no microSD card attached). Trying to find it on my network now.

@geerlingguy
Copy link
Owner Author

geerlingguy commented Oct 27, 2023

I can't figure out the login/password. I tried user/starfive, user/user, and riscv/starfive so far, to no avail.

Aha! It's root/milkv

@geerlingguy
Copy link
Owner Author

SSH password authentication was disabled, so to enable it (without messing with vi/nano over UART), I ran the oneliners:

sed -i '/PasswordAuthentication yes/s/^#//g' /etc/ssh/sshd_config
sed -i '/PermitRootLogin prohibit-password/s/^#//g' /etc/ssh/sshd_config
sed -i '/PermitRootLogin prohibit-password/s/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config

And restarted SSH with:

systemctl restart sshd

Now I can login via SSH!

@geerlingguy
Copy link
Owner Author

I'm in, but apt is incredibly slow (like in the single-digit-kilobytes per second range). Not sure why. Waiting for an install to complete so I can fetch some more info about the system. An apt upgrade might take all night at this range!

@geerlingguy
Copy link
Owner Author

geerlingguy commented Oct 27, 2023

The disk partition was not expanded initially, so I realized when I ran out of disk space (only about 4 GB is allocated by default), I had to run through the process documented on StarFive's website for extending the partition on the eMMC storage.

Once I did that, I wound up with about 11 GB of usable disk space.

Geekbench 6 preview downloaded about about 15 MB/sec, so not sure what was up with Apt...

Judging by VisionFive's warning not to upgrade, maybe I shouldn't try an apt upgrade on here yet?

@geerlingguy
Copy link
Owner Author

I'm unable to install Ansible via pip on the board because pip can't be upgraded to the latest version (easily at least), and thus cryptography libraries aren't getting installed.

So I'll run my Top500 benchmark through Ansible on my Mac, over SSH instead.

@christiancelona
Copy link

https://community.milkv.io/t/mars-cm-getting-started-guide-missing/845/5?u=christian

@christiancelona
Copy link

From the image provided by MilkV, following the instructions previously reported:
https://github.com/milkv-mars/mars-buildroot-sdk/releases/tag/20230723

sudo apt install python3-pip

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
build-essential bzip2 dpkg dpkg-dev fakeroot javascript-common
libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl
libbz2-1.0 libdpkg-perl libexpat1 libexpat1-dev libfakeroot
libfile-fcntllock-perl libjs-jquery libjs-sphinxdoc libjs-underscore
liblzma5 libperl5.36 libpython3-dev libpython3.11-dev patch perl perl-base
perl-modules-5.36 python3-dev python3-distutils python3-lib2to3
python3-pkg-resources python3-setuptools python3-wheel python3.11-dev
xz-utils zlib1g zlib1g-dev
Suggested packages:
bzip2-doc debsig-verify debian-keyring apache2 | lighttpd | httpd git bzr ed
diffutils-doc perl-doc libterm-readline-gnu-perl
| libterm-readline-perl-perl libtap-harness-archive-perl
python-setuptools-doc
The following NEW packages will be installed:
build-essential bzip2 dpkg-dev fakeroot javascript-common
libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl
libdpkg-perl libexpat1-dev libfakeroot libfile-fcntllock-perl libjs-jquery
libjs-sphinxdoc libjs-underscore libpython3-dev libpython3.11-dev patch
python3-dev python3-distutils python3-lib2to3 python3-pip python3-setuptools
python3-wheel python3.11-dev xz-utils zlib1g-dev
The following packages will be upgraded:
dpkg libbz2-1.0 libexpat1 liblzma5 libperl5.36 perl perl-base
perl-modules-5.36 python3-pkg-resources zlib1g
10 upgraded, 27 newly installed, 0 to remove and 825 not upgraded.
Need to get 30.1 MB of archives.
After this operation, 146 MB of additional disk space will be used.
Do you want to continue? [Y/n]

sudo apt install ansible

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
ansible-core ieee-data libselinux1 libyaml-0-2 python-babel-localedata
python3-anyio python3-argcomplete python3-babel python3-cffi-backend
python3-click python3-colorama python3-cryptography python3-dnspython
python3-h11 python3-h2 python3-hpack python3-httpcore python3-httplib2
python3-httpx python3-hyperframe python3-jinja2 python3-jmespath
python3-kerberos python3-libcloud python3-lockfile python3-markdown-it
python3-markupsafe python3-mdurl python3-netaddr python3-ntlm-auth
python3-packaging python3-passlib python3-pygments python3-pyparsing
python3-requests-ntlm python3-requests-toolbelt python3-resolvelib
python3-rfc3986 python3-rich python3-selinux python3-simplejson
python3-sniffio python3-tz python3-winrm python3-xmltodict python3-yaml
Suggested packages:
cowsay sshpass python-cryptography-doc python3-cryptography-vectors
python3-trio python3-aioquic python-jinja2-doc python-lockfile-doc ipython3
python-netaddr-docs python-pygments-doc ttf-bitstream-vera
python-pyparsing-doc
The following NEW packages will be installed:
ansible ansible-core ieee-data libyaml-0-2 python-babel-localedata
python3-anyio python3-argcomplete python3-babel python3-cffi-backend
python3-click python3-colorama python3-cryptography python3-dnspython
python3-h11 python3-h2 python3-hpack python3-httpcore python3-httplib2
python3-httpx python3-hyperframe python3-jinja2 python3-jmespath
python3-kerberos python3-libcloud python3-lockfile python3-markdown-it
python3-markupsafe python3-mdurl python3-netaddr python3-ntlm-auth
python3-packaging python3-passlib python3-pygments python3-pyparsing
python3-requests-ntlm python3-requests-toolbelt python3-resolvelib
python3-rfc3986 python3-rich python3-selinux python3-simplejson
python3-sniffio python3-tz python3-winrm python3-xmltodict python3-yaml
The following packages will be upgraded:
libselinux1
1 upgraded, 46 newly installed, 0 to remove and 824 not upgraded.
Need to get 30.3 MB of archives.
After this operation, 343 MB of additional disk space will be used.
Do you want to continue? [Y/n]

@christiancelona
Copy link

christiancelona commented Oct 28, 2023

I'm unable to install Ansible via pip on the board because pip can't be upgraded to the latest version (easily at least), and thus cryptography libraries aren't getting installed.

We use different images
https://github.com/milkv-mars/mars-buildroot-sdk/releases/tag/20230723

ansible --version ansible [core 2.14.11] config file = None configured module search path = ['/home/christian/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible ansible collection location = /home/christian/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.6 (main, Oct 8 2023, 05:06:43) [GCC 13.2.0] (/usr/bin/python3) jinja version = 3.1.2 libyaml = True

@geerlingguy
Copy link
Owner Author

To monitor the SoC temps, I installed lm-sensors and monitored with watch:

# apt install -y lm-sensors
# watch sensors
Every 2.0s: sensors                                                              starfive: Sat Oct 28 03:22:46 2023

120e0000.tmon-isa-0000
Adapter: ISA adapter
temp1:        +52.6 C

(That was with a heatsink only. SoC throttle limit seems to be 85°C.)

@geerlingguy
Copy link
Owner Author

geerlingguy commented Oct 28, 2023

It's funny, about 10 minutes after I boot the thing, I get a system message that it will suspend. Not sure why... and it doesn't actually suspend:

Broadcast message from user@starfive (Sat 2023-10-28 03:38:48 UTC):

The system will suspend now!

Looks like maybe it's a Gnome thing: https://forums.debian.net/viewtopic.php?t=156005 and https://discussion.fedoraproject.org/t/gnome-suspends-after-15-minutes-of-user-inactivity-even-on-ac-power/79801

@geerlingguy
Copy link
Owner Author

I tried using nmtui to configure a wifi connection (there were already details for a test connection in there), but after that it just output errors about trying to connect, like:

[ 6178.841606] [dhd] [wlan0] dhd_pri_stop : tx queue stopped
[ 6178.847110] [dhd] [wlan0] dhd_stop : Enter
[ 6178.851239] [dhd] dhd_stop: ######### called for ifidx=0 #########
[ 6178.877674] [dhd] dhd_stop: making dhdpub up FALSE
[ 6178.882480] [dhd] dhd_tcpack_suppress_set 377: already set to 0
[ 6178.888442] [dhd] [wlan0] dhd_stop : Exit
[ 6178.893123] [dhd] [wlan0] dhd_set_mac_address : macaddr = ae:34:61:e0:da:c8
[ 6178.900123] [dhd] CFG80211-ERROR) wl_cfg80211_macaddr_sync_reqd : no macthing if type
[ 6178.908044] [dhd] dhd_set_mac_addr_handler: interface info not available/down 
[ 6179.014288] [dhd] [wlan0] dhd_open : Enter
[ 6179.018445] [dhd] dhd_open: ######### called for ifidx=0 #########
[ 6179.047426] [dhd] CFG80211-ERROR) wl_cfg80211_generate_mac_addr : wl_cfg80211_generate_mac_addr:generated new MAC=36:85:ba:e6:7b:50 
[ 6179.065959] [dhd] CFG80211-ERROR) __wl_update_wiphybands : error reading txbf_bfe_cap (-23)
[ 6179.075253] [dhd] CFG80211-ERROR) __wl_update_wiphybands : error reading txbf_bfr_cap (-23)
[ 6179.101182] [dhd] CFG80211-ERROR) init_roam_cache : roamscan_mode iovar failed. -23
[ 6179.108860] [dhd] CFG80211-ERROR) wl_cfg80211_up : Failed to enable RCC.
[ 6179.116226] [dhd] [wlan0] dhd_open : Exit ret=0
[ 6179.120789] [dhd] [wlan0] dhd_pri_open : tx queue started
[ 6179.127869] [dhd] [wlan0] _dhd_set_mac_address : MACID ae:34:61:e0:da:c8 is overwritten
[ 6179.237736] [dhd] [wlan0] wl_run_escan : LEGACY_SCAN sync ID: 184, bssidx: 0
[ 6181.683969] [dhd] CFG80211-ERROR) wl_set_auth_type : set auth failed (-2)
[ 6181.690788] [dhd] CFG80211-ERROR) wl_config_assoc_security : Invalid auth type
[ 6181.698024] [dhd] CFG80211-ERROR) wl_cfg80211_connect : config assoc security failed
[ 6181.705772] [dhd] CFG80211-ERROR) wl_cfg80211_connect : connect error (-2)

@eshattow
Copy link

With regard to gnome not functioning after apt upgrade of the vendor provided OS via Debian unstable package repo, gnome-shell (and gdm3...) count among the packages that are failing to build at the moment on the Debian unstable repo (task-gnome-desktop is uninstallable). For a while now package building machines as part of Debian infrastructure ran into a Linux kernel regression causing builds to randomly fail with riscv64 on real hardware. This regression was identified and reverted in stable kernel series 6.5.8 which was only just recently packaged for Debian unstable and may/may not yet be rolled out to actually be running on the build machines. You can verify this with a Debian QuIck Baker image in a virtual machine for example https://people.debian.org/~gio/dqib/ to get a baseline riscv64 Debian unstable system, and then following along of https://buildd.debian.org/status/architecture.php?a=riscv64&suite=sid for an overview of what packages are stuck in the re-build churn.

@geerlingguy
Copy link
Owner Author

A number of the Phoronix Test Suite tests failed, for example, trying to do the mp3 encode test:

UNAME_MACHINE = riscv64
UNAME_RELEASE = 5.15.0
UNAME_SYSTEM  = Linux
UNAME_VERSION = #9 SMP Sun Oct 8 17:14:43 CST 2023
configure: error: cannot guess build type; you must specify one
make: *** No targets specified and no makefile found.  Stop.
make: *** No rule to make target 'install'.  Stop.

And then for things like the linux kernel build, it ran out of space. For now I'll leave those tests out, 16 GB isn't that much space to play with :)

@geerlingguy
Copy link
Owner Author

I still can't get WiFi to connect.

# ip link
...
4: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DORMANT mode DORMANT group default qlen 1000
    link/ether ee:49:09:26:18:b5 brd ff:ff:ff:ff:ff:ff permaddr b8:2d:28:25:5d:0e

nmtui upon activating a WiFi link just sits Connecting... while error messages like those earlier are printed in dmesg.

That was with my 5 GHz network. Trying two different 2.4 GHz networks (one is on an older router that works better with ancient or weird WiFi hardware), I could get nothing from either of those too (same errors).

So maybe the WiFi driver's a bit flaky in the OS image I have installed?

@geerlingguy
Copy link
Owner Author

Checking on the JH7110 Linux kernel Upstreaming Status, it looks like most interfaces are upstream now, with the rest on their way. Quite nice! And happening more quickly than many of the Arm SoCs these days...

@geerlingguy
Copy link
Owner Author

Testing PCIe:

root@starfive:~# sudo lspci -vvvv
00:00.0 PCI bridge: PLDA XpressRich-AXI Ref Design (rev 02) (prog-if 00 [Normal decode])
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 0
	Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
	Memory behind bridge: 30000000-300fffff [size=1M] [32-bit]
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR+ NoISA- VGA- VGA16- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [80] Express (v2) Root Port (Slot+), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0
			ExtTag+ RBE+
		DevCtl:	CorrErr- NonFatalErr- FatalErr- UnsupReq-
			RlxdOrd+ ExtTag+ PhantFunc- AuxPwr- NoSnoop+
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr+ NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
		LnkCap:	Port #1, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s <64ns, L1 <1us
			ClockPM- Surprise- LLActRep- BwNot+ ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 5GT/s, Width x1
			TrErr- Train- SlotClk- DLActive- BWMgmt+ ABWMgmt-
		SltCap:	AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
			Slot #0, PowerLimit 0W; Interlock- NoCompl-
		SltCtl:	Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
			Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
		SltSta:	Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
			Changed: MRL- PresDet- LinkState-
		RootCap: CRSVisible-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
		DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ NROPrPrP- LTR+
			 10BitTagComp- 10BitTagReq- OBFF Not Supported, ExtFmt+ EETLPPrefix-
			 EmergencyPowerReduction Not Supported, EmergencyPowerReductionInit-
			 FRS- LN System CLS Not Supported, TPHComp- ExtTPHComp- ARIFwd-
			 AtomicOpsCap: Routing- 32bit- 64bit- 128bitCAS-
		DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- LTR- 10BitTagReq- OBFF Disabled, ARIFwd-
			 AtomicOpsCtl: ReqEn- EgressBlck-
		LnkCap2: Supported Link Speeds: 2.5-5GT/s, Crosslink- Retimer- 2Retimers- DRS-
		LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
			 Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
			 Compliance Preset/De-emphasis: -6dB de-emphasis, 0dB preshoot
		LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete- EqualizationPhase1-
			 EqualizationPhase2- EqualizationPhase3- LinkEqualizationRequest-
			 Retimer- 2Retimers- CrosslinkRes: unsupported
	Capabilities: [e0] MSI: Enable- Count=1/32 Maskable+ 64bit+
		Address: 0000000000000000  Data: 0000
		Masking: 00000000  Pending: 00000000
	Capabilities: [f8] Power Management version 3
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [100 v1] Vendor Specific Information: ID=1556 Rev=1 Len=008 <?>
	Capabilities: [200 v2] Advanced Error Reporting
		UESta:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UEMsk:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UESvrt:	DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
		CESta:	RxErr+ BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr-
		CEMsk:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr+
		AERCap:	First Error Pointer: 00, ECRCGenCap- ECRCGenEn- ECRCChkCap+ ECRCChkEn-
			MultHdrRecCap- MultHdrRecEn- TLPPfxPres- HdrLogCap-
		HeaderLog: 00000000 00000000 00000000 00000000
		RootCmd: CERptEn- NFERptEn- FERptEn-
		RootSta: CERcvd- MultCERcvd- UERcvd- MultUERcvd-
			 FirstFatal- NonFatalMsg- FatalMsg- IntMsg 0
		ErrorSrc: ERR_COR: 0000 ERR_FATAL/NONFATAL: 0000
lspci: Unable to load libkmod resources: error -2

01:00.0 Non-Volatile memory controller: KIOXIA Corporation Device 0010 (rev 01) (prog-if 02 [NVM Express])
	Subsystem: KIOXIA Corporation Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 53
	Region 0: Memory at 30000000 (64-bit, non-prefetchable) [size=16K]
	Capabilities: [80] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [90] MSI: Enable- Count=1/32 Maskable+ 64bit+
		Address: 0000000000000000  Data: 0000
		Masking: 00000000  Pending: 00000000
	Capabilities: [b0] MSI-X: Enable+ Count=65 Masked-
		Vector table: BAR=0 offset=00002000
		PBA: BAR=0 offset=00003000
	Capabilities: [c0] Express (v2) Endpoint, MSI 00
		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s unlimited, L1 unlimited
			ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset+ SlotPowerLimit 0W
		DevCtl:	CorrErr- NonFatalErr- FatalErr- UnsupReq-
			RlxdOrd- ExtTag+ PhantFunc- AuxPwr- NoSnoop- FLReset-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
		LnkCap:	Port #0, Speed 16GT/s, Width x4, ASPM L1, Exit Latency L1 <32us
			ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 5GT/s (downgraded), Width x1 (downgraded)
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ NROPrPrP- LTR+
			 10BitTagComp+ 10BitTagReq- OBFF Not Supported, ExtFmt+ EETLPPrefix-
			 EmergencyPowerReduction Not Supported, EmergencyPowerReductionInit-
			 FRS- TPHComp- ExtTPHComp-
			 AtomicOpsCap: 32bit- 64bit- 128bitCAS-
		DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- LTR- 10BitTagReq- OBFF Disabled,
			 AtomicOpsCtl: ReqEn-
		LnkCap2: Supported Link Speeds: 2.5-16GT/s, Crosslink- Retimer+ 2Retimers+ DRS-
		LnkCtl2: Target Link Speed: 16GT/s, EnterCompliance- SpeedDis-
			 Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
			 Compliance Preset/De-emphasis: -6dB de-emphasis, 0dB preshoot
		LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete- EqualizationPhase1-
			 EqualizationPhase2- EqualizationPhase3- LinkEqualizationRequest-
			 Retimer- 2Retimers- CrosslinkRes: unsupported
	Capabilities: [100 v2] Advanced Error Reporting
		UESta:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UEMsk:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UESvrt:	DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
		CESta:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr-
		CEMsk:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr+
		AERCap:	First Error Pointer: 00, ECRCGenCap+ ECRCGenEn- ECRCChkCap+ ECRCChkEn-
			MultHdrRecCap- MultHdrRecEn- TLPPfxPres- HdrLogCap-
		HeaderLog: 00000000 00000000 00000000 00000000
	Capabilities: [150 v1] Virtual Channel
		Caps:	LPEVC=0 RefClk=100ns PATEntryBits=1
		Arb:	Fixed- WRR32- WRR64- WRR128-
		Ctrl:	ArbSelect=Fixed
		Status:	InProgress-
		VC0:	Caps:	PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
			Arb:	Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
			Ctrl:	Enable+ ID=0 ArbSelect=Fixed TC/VC=ff
			Status:	NegoPending- InProgress-
	Capabilities: [260 v1] Latency Tolerance Reporting
		Max snoop latency: 0ns
		Max no snoop latency: 0ns
	Capabilities: [300 v1] Secondary PCI Express
		LnkCtl3: LnkEquIntrruptEn- PerformEqu-
		LaneErrStat: 0
	Capabilities: [360 v1] Data Link Feature <?>
	Capabilities: [380 v1] Physical Layer 16.0 GT/s <?>
	Capabilities: [400 v1] L1 PM Substates
		L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1- L1_PM_Substates+
			  PortCommonModeRestoreTime=60us PortTPowerOnTime=150us
		L1SubCtl1: PCI-PM_L1.2- PCI-PM_L1.1- ASPM_L1.2- ASPM_L1.1-
			   T_CommonMode=0us LTR1.2_Threshold=0ns
		L1SubCtl2: T_PwrOn=10us
	Capabilities: [470 v1] Lane Margining at the Receiver <?>
	Kernel driver in use: nvme
root@starfive:~# lsblk
NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
...
nvme0n1      259:0    0  1.9T  0 disk 
|-nvme0n1p1  259:1    0  256M  0 part 
`-nvme0n1p2  259:2    0  1.9T  0 part 

@geerlingguy
Copy link
Owner Author

geerlingguy commented Oct 29, 2023

I formatted the 2TB NVMe SSD, then ran my disk benchmarks, and got 150 MB/sec for fio, and 250 MB/sec for 1M sequential read/write via iozone. Not amazing, but a lot better than built-in eMMC!

See full benchmark results in OP.

@geerlingguy
Copy link
Owner Author

@christiancelona - Do you know why the buildroot image for these devices is still on kernel 5.15.x?

@christiancelona
Copy link

christiancelona commented Oct 30, 2023

I would have preferred not to write it to you :)
https://lupyuen.github.io/articles/display3

With Ubuntu 23.10 the onboard GPU is not supported, USB are not supported by the 6.2 kernel and the OS do not work with the 6.5 kernel.

I believe that there is little point in engaging in benchmarks of this SoC, except in the case in which you want to measure the benefits brought by good software support, which has so far been absent.

I'm waiting for the new integrated SMB in kernel that might make my SBC more suitable for my purposes. Up until now I have always used Raspberry Pi but the latest one is absolutely not in my purchase plans and not because of the cost. For those who wanted to use the Milk-V Mars SBC as a low-power desktop, the biggest obstacle to using the new kernels was certainly the display controller driver for Verisilicon DC8200 (for me the Chinese ideograms are a big obstacle) and an HMDI driver, now patched, check again the documentation at the line HDMI/ DC8200.

I am waiting for the new images from Armbian (Armbian 23.11 Topi release, announced today) on November 1st or 2nd a Debian Topi should be ready to try, or in future DietPi too.

But perhaps you have clearer ideas about the propagation time of new kernels in Linux distributions.
Tonight I want to try an intermediate solution, Debian Backports provides new packages with new features on supported Debian stable releases, switching /etc/apt/sources.list to deb http://deb.debian.org/debian bookworm-backports main.

@christiancelona
Copy link

christiancelona commented Oct 30, 2023

Update:
Skipping acquire of configured file 'main/binary-riscv64/Packages' as repository 'http://deb.debian.org/debian bookworm-backports InRelease' doesn't support architecture 'riscv64'

It's better not to follow my experiments, I updated everything and still lost the graphic environment. I'm starting from scratch.

@christiancelona
Copy link

christiancelona commented Oct 31, 2023

Milk-V Mars, sbc-bench v0.9.49 result: http://ix.io/4KoX
StarFive JH7110 | 1500 MHz | 5.15 | Armbian 23.11.0-trunk.243 lunar riscv64/riscv | 4000 | 1174 | 24900 | 870 | 790 | - |

@geerlingguy
Copy link
Owner Author

@christiancelona - Interesting, it looks like every score besides the memcpy/memset scores was slower in your run (compared to the one I ran on the StarFive kernel).

@christiancelona
Copy link

christiancelona commented Oct 31, 2023

I wondered if it could depend on the software and I redid the tests with a Raspberry Pi 4B and Armbian (non the same, lunar vs jammy).

RPi 4 Model B Rev 1.4, sbc-bench v0.9.49 result: http://ix.io/4Kpg
BCM2711 Rev B0 | 1800 MHz | 6.1 | Armbian 23.11.0-trunk.243 jammy arm64 | 5580 | 1704 | 36240 | 2400 | 2940 | - |

Remember that we are comparing two slightly different hardware too. I couldn't boot from SD with the same image as you, my testing time is over today.

@ThomasKaiser
Copy link

@christiancelona with 6.5 it doesn't look better (memory latency and CPU clockspeeds the same but scores for whatever reason slightly lower):

Kernel Clockspeed Distro 7-zip multi 7-zip single AES memcpy memset
5.15 1500 MHz Lunar riscv64 4000 1174 24900 870 790
6.5 1500 MHz Lunar riscv64 3910 1114 24100 870 840

@christiancelona
Copy link

christiancelona commented Oct 31, 2023

Thank you. I installed the StarFive image, they are different for SD or whatever. Indeed, the difference in performance is also noticeable in use, not only from the benchmarks, the system is more responsive.

I have no idea what changes between kernels, other than the version, at the moment the image provided by the SoC manufacturer is the best, despite being older. Furthermore, the SoC temperature is now lower.

@rhinot
Copy link

rhinot commented Oct 31, 2023

Hey Folks - How can I help contribute here?
I have a Milk-V Mars. What do you recommend as an image at this point?

@carbonfix
Copy link

@geerlingguy The process for re-flashing the eMMC image has been updated to the document:

https://milkv.io/docs/mars/compute-module/boot

@rhinot
Copy link

rhinot commented Nov 6, 2023

In case it helps...
Milk-V Mars, sbc-bench v0.9.50 result: http://ix.io/4KNT
StarFive JH7110 | 1500 MHz | 6.1.59 | Debian GNU/Linux trixie/sid riscv64 | 4090 | 1191 | 24600 | 865 | 828 | - |

Similar to @ThomasKaiser & @christiancelona's Armbian Lunar numbers on 5.15 & 6.5, although slightly higher.
Big differences: 8GB version, counterfeit SD, VNC service running, DietPi stock build from Nov 3

@platima
Copy link
Contributor

platima commented Nov 6, 2023

Attaching to UART using the same pins as Mars (see Serial Console docs), I was able to monitor boot output...

U-Boot SPL 2021.10 (Oct 08 2023 - 17:13:43 +0800)
LPDDR4: 4G version: g8ad50857.
Trying to boot from SPI

OpenSBI v1.2
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|___./_____|
        | |
        |_|

Platform Name             : StarFive VisionFive V2
Platform Features         : medeleg
Platform HART Count       : 5
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 4000000Hz
Platform Console Device   : uart8250
Platform HSM Device       : ---
Platform PMU Device       : ---
Platform Reboot Device    : pm-reset
Platform Shutdown Device  : pm-reset
Platform Suspend Device   : ---
Firmware Base             : 0x40000000
Firmware Size             : 392 KB
Firmware RW Offset        : 0x40000
Runtime SBI Version       : 1.0

Domain0 Name              : root
Domain0 Boot HART         : 1
Domain0 HARTs             : 0*,1*,2*,3*,4*
Domain0 Region00          : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain0 Region01          : 0x0000000040000000-0x000000004003ffff M: (R,X) S/U: ()
Domain0 Region02          : 0x0000000040040000-0x000000004007ffff M: (R,W) S/U: ()
Domain0 Region03          : 0x0000000000000000-0xffffffffffffffff M: (R,W,X) S/U: (R,W,X)
Domain0 Next Address      : 0x0000000040200000
Domain0 Next Arg1         : 0x0000000042200000
Domain0 Next Mode         : S-mode
Domain0 SysReset          : yes
Domain0 SysSuspend        : yes

Boot HART ID              : 1
Boot HART Domain          : root
Boot HART Priv Version    : v1.11
Boot HART Base ISA        : rv64imafdcbx
Boot HART ISA Extensions  : none
Boot HART PMP Count       : 8
Boot HART PMP Granularity : 4096
Boot HART PMP Address Bits: 34
Boot HART MHPM Count      : 2
Boot HART MIDELEG         : 0x0000000000000222
Boot HART MEDELEG         : 0x000000000000b109


U-Boot 2021.10 (Oct 08 2023 - 17:13:43 +0800)

CPU:   rv64imacu_zba_zbb
Model: StarFive VisionFive V2
DRAM:  4 GiB
cdns3_bind: unsupported dr_mode
MMC:   sdio0@16010000: 0, sdio1@16020000: 1
Loading Environment from SPIFlash... SF: Detected gd25lq128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
*** Warning - bad CRC, using default environment

StarFive EEPROM format v2
...

It looks like it does automatically boot into Debian, and it says an eth0 link is up... (this is with no microSD card attached). Trying to find it on my network now.

Had this same issue last week testing the non-CM board. Corrupt SBC config on SPI flash seemingly resulted in it looking for kernel on eMMC as default, but their image wanted SD card. I flashed both, booted, then changed /boot/extlinux/extlinux.cfg to use mmcblk0 so no SD card required, and it works a treat.

Next week I'm going to try to flash OpenSBI again with correct config, see if that does it. Released eMMC image for now anyway; https://plati.ma/milk-v-mars/ (should have seen this post and enabled password-full SSH, dang it)

Cheers for your RV contributions mate!

@mr-c
Copy link

mr-c commented Nov 8, 2023

Update: Skipping acquire of configured file 'main/binary-riscv64/Packages' as repository 'http://deb.debian.org/debian bookworm-backports InRelease' doesn't support architecture 'riscv64'

@christiancelona Switch to sid trixie (the testing development version of the next stable Debian release, where riscv64 is a first class architecture) from bookwarm in your /etc/apt/sources.list

@platima
Copy link
Contributor

platima commented Nov 8, 2023

Switch to trixie (the testing version of the next stable Debian release, where riscv64 is a first class architecture) from bookwarm in your /etc/apt/sources.list

OH this repo is live? I am so damn excited; was looking for it the other day when messing with a Mars SBC. Thank you kindly!

@mr-c
Copy link

mr-c commented Nov 8, 2023

Switch to trixie (the testing version of the next stable Debian release, where riscv64 is a first class architecture) from bookwarm in your /etc/apt/sources.list

OH this repo is live? I am so damn excited; was looking for it the other day when messing with a Mars SBC. Thank you kindly!

Whoops, I should have tested that. Use sid instead, I guess the riscv64 packages haven't migrated to Trixie yet.

@platima
Copy link
Contributor

platima commented Nov 8, 2023

Whoops, I should have tested that. Use sid instead, I guess the riscv64 packages haven't migrated to Trixie yet.

You set me up, just to let me down 💔

@eshattow
Copy link

eshattow commented Nov 8, 2023

Whoops, I should have tested that. Use sid instead, I guess the riscv64 packages haven't migrated to Trixie yet.

/etc/apt/sources.list.d/debian.sources:

Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: unstable
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg

/etc/apt/sources.list.d/debian-experimental.sources:

Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: experimental
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg

There is a PCB revision needed to fix some problems and so the next batch of Mars CM is delayed until later this month (November 2023). Until I get a Mars CM in-hand I am following along with Debian riscv64 progress by a running qemu instance and the DQIB image as mentioned above.

@platima
Copy link
Contributor

platima commented Nov 9, 2023

@eshattow oh super interesting to know! Can I ask what problems are being fixed if you have any insight?

Ripper to see rv64 in unstable now, did not recall seeing that previously. Looks like it's got kernel 6.5 in there too; https://packages.debian.org/unstable/linux-image-6.5.0-4-riscv64

I've got a Mars SBC (not CM) I am tempted to test with.

@eshattow
Copy link

eshattow commented Nov 9, 2023

@platima I too am curious. That was the summary of a reply from the distributor customer support person. 🤷

@platima
Copy link
Contributor

platima commented Nov 9, 2023 via email

@rhinot
Copy link

rhinot commented Nov 11, 2023

@platima I installed the linux-image-riscv64 which installs 6.5.10-1 and a few other utils.

Install goes fine, but haven't figured how to get the system to boot that kernel (no grub). Happy to try any ideas you have, so you don't have to switch over for nothing.

@platima
Copy link
Contributor

platima commented Nov 17, 2023 via email

@rhinot
Copy link

rhinot commented Nov 18, 2023

Thanks, @platima!

That was helpful, as I tried loading the 6.5 kernel, it failed, and this allowed me to fall back to 6.1.
For other's reference, I also found this extlinux.conf sample clarifying.

Do you know where I can find what failed when the system tried to boot into my 6.5 kernel?
I tried journalctl, but there is nothing even with the timestamps of the attempted boot with that kernel.

@platima
Copy link
Contributor

platima commented Nov 18, 2023 via email

@eshattow
Copy link

eshattow commented Dec 30, 2023

milkv_marscm101_flatscan_lossy_face
milkv_marscm101_flatscan_lossy_obverseflip
Flatbed scan of rev 1.01 (bottom scan is flipped and aligned in post-process so it matches where components are viewed from the top down).

Identified chip markings overall:

  • AXP15060 N2103DB 64F1
  • GigaDevice HJ2113 25LQ128EWIG AP2V570
  • MOTORCOMM YT8531C (...?)
  • CXMt CXDB5CCAM MK 2250 AP23210390900 (4GB model. Reportedly this would be CXDB4ABAM on 2G/eMMC8G model.)
  • 24C04F 21626P (looking for a datasheet? search instead BL24c04f)

milkv_marscm101_flatscan_lossy_obverse_eepromdetail
Detail view from above obverse scan of eeprom chip. Note the markings in contrast to Milk-V vendor SDK devicetree eeprom hack mars-buildroot-sdk.git/linux/arch/riscv/boot/dts/starfive/jh7110-milkv-mars-cm.dtsi:

        eeprom@50 {
                compatible = "atmel,24c02";
                reg = <0x50>;
                pagesize = <16>;
        };

The eeprom here has wrong data as it indicates a 16GB eMMC (E016) and there is no eMMC (E000). Correct this by shorting the eeprom Write Protect pin at "EN" test point to ground and write new value from U-Boot:

milkv_mars_cm_eeprom_wp_disable
IMG_20240417_154541

mac
--------EEPROM INFO--------
Vendor : MILK-V
Product full SN: MARC-V10-2340-D004E016-00001234
...
mac product_id MARC-V10-2340-D004E000-00001234
mac write_eeprom
Programming passed.

@eshattow
Copy link

eshattow commented Jan 18, 2024

Fun fact you can use the U-Boot 'dhcp' command to set up the network PHY ahead of loading a kernel. Otherwise MOTORCOMM_PHY in addition to defconfig is needed for mainline Linux kernel, and if you want SD Card function that will be I2C_DESIGNWARE_PLATFORM && MFD_AXP20X_I2C && REGULATOR_AXP20X. No patches needed for SDCard and it seems "good enough" to use the in-tree DTB: starfive/jh7110-starfive-visionfive-2-v1.3b.dtb (although it doesn't exactly match the Mars CM hardware).

The official debian-installer can be run successfully in EFI mode:
https://d-i.debian.org/daily-images/riscv64/

@eshattow
Copy link

eshattow commented Jan 24, 2024

Build firmware

Adapted from U-Boot documentation: suggested build procedure for Milk-V Mars.

Build U-Boot with patches for Mars CM and UART boot:

mkdir $HOME/build

git clone https://github.com/riscv-software-src/opensbi.git $HOME/source/opensbi.git
git -C $HOME/source/opensbi.git checkout d4d2582e
make O=$HOME/build/opensbi -C $HOME/source/opensbi.git PLATFORM=generic

git clone https://source.denx.de/u-boot/u-boot.git $HOME/source/u-boot.git
git -C $HOME/source/u-boot.git checkout v2024.07-rc2

# efi_loader-improve-device-tree-loading.patch (does not apply cleanly, 3-way merge and skip as needed)
# https://patchwork.ozlabs.org/project/uboot/list/?series=404590
curl https://patchwork.ozlabs.org/series/404590/mbox/ | git -C $HOME/source/u-boot.git am -3
until git -C $HOME/source/u-boot.git am --skip ; do : ; done

# Add-Starfive-JH7110-Cadence-USB-driver.patch
# https://patchwork.ozlabs.org/project/uboot/list/?series=405474
curl https://patchwork.ozlabs.org/series/405474/mbox/ | git -C $HOME/source/u-boot.git am

# 1-2-v2-board-starfive-support-Pine64-Star64-board.patch
# https://patchwork.ozlabs.org/project/uboot/list/?series=406115
curl https://patchwork.ozlabs.org/series/406115/mbox/ | git -C $HOME/source/u-boot.git am

# board-starfive-add-Milk-V-Mars-CM-support.patch (v3) (small merge conflict in doc/board/starfive/index.rst)
# https://patchwork.ozlabs.org/project/uboot/list/?series=406147
curl https://patchwork.ozlabs.org/series/406147/mbox/ | git -C $HOME/source/u-boot.git am -3

make O=$HOME/build/u-boot -C $HOME/source/u-boot.git starfive_visionfive2_defconfig
echo "CONFIG_CMD_ERASEENV=y" >> $HOME/build/u-boot/.config
echo "CONFIG_CMD_NVEDIT_LOAD=y" >> $HOME/build/u-boot/.config
make O=$HOME/build/u-boot -C $HOME/source/u-boot.git oldconfig
make O=$HOME/build/u-boot -C $HOME/source/u-boot.git OPENSBI=$HOME/build/opensbi/platform/generic/firmware/fw_payload.bin

Deliverables attached as u-boot-20240506-404590-405361-405474-405683-loaderase.zip (572KB):
$HOME/build/u-boot/spl/u-boot-spl.bin.normal.out
$HOME/build/u-boot/u-boot.itb

Note the vendor U-Boot devicetree changeset for SD Card on Milk-V Mars CM Lite is applied at runtime depending if your EEPROM indicates no eMMC (value "E000"). First production runs of Milk-V Mars CM Lite had wrong value "E016" in EEPROM data which is easily corrected. Milk-V technical support has acknowledged this concern as of 14th Apr 2024:

"There may be a bug in the process of writing eeprom data during our functional test. We will check and correct it in the next production."

Note the vendor Linux devicetree changeset for SD Card on Milk-V Mars CM Lite does not appear yet in mainline Linux.

Recovery and flashing firmware

Serial terminal tio is known to work with a CP2102N UART adapter and tolerates the excess NAK bug present in JH7110 MaskROM XMODEM loader implementation. Milk-V Mars CM is factory pre-loaded with firmware flashed to SPI NOR consisting of a Secondary Program Loader (SPL) and a payload image that is flashed to SPI NOR at an offset. SPL and payload are from U-Boot software which includes OpenSBI dependency.

JH7110 UART recovery using U-Boot:

  1. Connect UART adapter from host with tio: tio /dev/ttyUSB0
  2. Set nRPIBOOT switch enable on carrier board for UART operation and power on
  3. Observe the C character repeats while waiting for XMODEM transfer
  4. Upload XMODEM-1K ctrl+t x u-boot-spl.bin.normal.out SPL and there will be repeating . character during the transfer for approximately 16 seconds duration ending with |
  5. U-Boot SPL will execute and then expects the u-boot.itb payload as YMODEM transfer
  6. Upload YMODEM ctrl+t y u-boot.itb payload and there will be repeating . character during the transfer for approximately 5 minutes duration ending with |
  7. Continue to flash firmware using U-Boot (below) and disconnect nRPIBOOT to resume SPI NOR boot operation.

Flashing firmware to SPI NOR using U-Boot:

env default -f -a
sf probe

loady $loadaddr
# ctrl+t y (tio) u-boot-spl.bin.normal.out
sf update $loadaddr 0 $filesize

loady $loadaddr
# ctrl+t y (tio) u-boot.itb
sf update $loadaddr 100000 $filesize

Interrupt the bootcmd countdown at reset and clean the environment variable storage to complete the update process:

env erase
env load
env set eth2addr aa:bb:cc:dd:ee:ff  # OPTIONAL: mac address of additional network port on CM4 carrier board
env save
reset

Debian Installer

Debian installer netinst riscv64 daily builds are working unmodified as of April 2024 for SD Card or eMMC as a storage target. For installation to storage targets on PCIe host bus it will be necessary to use a custom kernel and device-tree. Installation notes here refer to TFTP method for source media but can also be done via UART (this will probably take many hours to transfer) if it is not possible to set up a local TFTP server. SD Card and PCIe attached storage devices may also be viable source media if accessible from U-Boot. USB is not yet functional on Mars CM/Lite in U-Boot.

Download debian-installer and debian-installer/device-tree as local copy

curl -L https://d-i.debian.org/daily-images/riscv64/daily/netboot/netboot.tar.gz | tar xz ./debian-installer
wget -np -nH --cut-dirs=3 -r -R "index.html*" -P debian-installer https://d-i.debian.org/daily-images/riscv64/daily/device-tree/
(Optional) Modify debian-installer with kernel modules and package from patched kernel
fakeroot  # enter fakeroot environment to preserve initrd permissions
gzip -dc debian-installer/riscv64/initrd.gz | cpio -id --directory=initrd
curl -L https://github.com/geerlingguy/sbc-reviews/files/15277673/linux-image-6.9.0-rc7-jh7110-00036-gd479e01e625a_1_riscv64.deb.gz | gzip -dc | tee initrd/linux-image-custom.deb | dpkg -x - initrd/custom
gzip -dc initrd/custom/boot/vmlinuz-* > debian-installer/riscv64/linux-custom
mv initrd/lib/modules initrd/custom/
mv initrd/custom/lib/modules initrd/lib/
mv initrd/custom/usr/lib/* debian-installer/device-tree-custom
find initrd -path initrd/custom -prune -o -printf '%P\0' | cpio -0oH newc --directory=initrd | gzip -c > debian-installer/riscv64/initrd-custom.gz
exit  # leave fakeroot environment

rm -fr initrd  # cleanup

Prepare TFTP server locally

TFTP is used to serve installer files because it's quick and you'll need network access anyways in debian-installer.

apt install atftpd
systemctl start atftpd
cp -r debian-installer /srv/tftp/

We'll refer to as $tftp_ip:/debian-installer for the example. Also download debian-installer riscv64 daily jh7110-starfive-visionfive-2-v1.3b.dtb and make available as $tftp_ip:/debian-installer/riscv64/jh7110-starfive-visionfive-2-v1.3b.dtb on the TFTP server.

Installation

Reset the Mars CM and command U-Boot from tio:

Standard debian-installer netinst (no PCIe host)
env set tftp_ip 1.2.3.4    # adjust as the TFTP server where to connect
dhcp $kernel_addr_r $tftp_ip:/debian-installer/riscv64/linux
dhcp $fdt_addr_r $tftp_ip:/debian-installer/device-tree/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb
dhcp $ramdisk_addr_r $tftp_ip:/debian-installer/riscv64/initrd.gz
env set bootargs 'initrd='$ramdisk_addr_r',0x'$filesize
bootefi $kernel_addr_r $fdt_addr_r
Alternate: Custom debian-installer netinst (with PCIe host)
env set tftp_ip 1.2.3.4    # adjust as the TFTP server where to connect
dhcp $kernel_addr_r $tftp_ip:/debian-installer/riscv64/linux-custom
dhcp $fdt_addr_r $tftp_ip:/debian-installer/device-tree-custom/starfive/jh7110-milkv-mars.dtb
dhcp $ramdisk_addr_r $tftp_ip:/debian-installer/riscv64/initrd-custom.gz
env set bootargs 'initrd='$ramdisk_addr_r',0x'$filesize
bootefi $kernel_addr_r $fdt_addr_r

Advice on debian-installer use:

  • When asked for setting a root password then enter twice an empty root password to enable sudo for the user account.
  • Guided partitioning defaults are fine. An example of 8GB SD card with manual partitioning would be 63MB EFI System Partition following the automatic unused 1MB alignment offset, 7GB Linux root partition, and "max" remainder 1GB as Linux swap partition.
  • Software selection should be the default (SSH server, standard system utilities) only.
  • When asked if you want to install for removable media a default "No" answer installs Grub2 on EFI System Partition as EFI/debian/grubriscv64.efi while a "Yes" answer will place an additional copy of the Grub2 bootloader as EFI/BOOT/BOOTRISCV64.EFI. There's no advantage to having an extra copy of Grub2 taking up space on the EFI System Partition so the default is fine here.
Finish the installation

At this last step of the debian-installer ctrl+a n to next screen window 2 shell:

# optional: Install custom kernel image
mount -o bind /dev/pts /target/dev/pts
chroot /target /bin/bash  # enter chroot
wget -O- https://github.com/geerlingguy/sbc-reviews/files/15276410/linux-image-6.9.0-rc7-jh7110-rvdtnext2config2pcie16extra.tar.gz | tar xvf -
apt remove -y 'linux-image-*'
dpkg -i linux-image-*.deb
exit  # leave chroot

# required: A fresh EFI System Partition does not have any devicetree files so we must copy something there.
cp  -rT /target/usr/lib/linux-image-* /target/boot/efi/dtb

To resume the installer ctrl+a p to previous screen window 1 installer and confirm Continue to reboot.

(Extra) Using debian-installer as post-installation tool to install custom kernel package

When using debian-installer as a rescue environment note that the clock and network are not set up until later in the installer process.

  • Select a language
    after "Select your location" ctrl+a,n to next screen window 2 shell
cat /proc/partitions  # see available storage names i.e. mmcblk0

mount /dev/mmcblk0p2 /mnt
mount /dev/mmcblk0p1 /mnt/boot/efi
cp /linux-image-custom.deb /mnt/tmp/
for i in /dev /dev/pts /proc /run /sys /sys/firmware/efi/efivars; do mount -o bind $i /mnt$i ; done
chroot /mnt /bin/bash
dpkg -i /tmp/linux-image-custom.deb
cp -rT /usr/lib/linux-image-$(uname -r) /boot/efi/dtb
exit
reboot

U-Boot EFI boot manager will use EFI/BOOT/BOOTRISCV64.EFI by default if found even if there is no configured EFI boot entry, but currently does not load the devicetree named by $fdtfile U-Boot environment variable. An additional U-Boot EFI boot entry for Debian GRUB EFI may be created with U-Boot command eficonfig, and then menu item Add Boot Option:

Description: `Debian`
=> File: `mmc 0:1 EFI\debian\grubriscv64.efi` or `mmc 1:1 EFI\debian\grubriscv64.efi` depending on SD Card or eMMC operation, NVMe i.e.
=> Fdt File: `mmc 0:1/dtb\starfive\jh7110-starfive-visionfive-2-v1.3b.dtb`  (or starfive\jh7110-milkv-mars.dtb if available).

Remember to also Change Boot Order so your boot entry is ordered first ahead of the global EFI boot entry for each storage containing an EFI System Partition.

Linux Kernel, EFI stub, and Devicetree

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $HOME/source/linux.git

# Accepted Milk-V Mars dts for-next https://patchwork.kernel.org/project/linux-riscv/list/?series=848676
git -C $HOME/source/linux.git remote add conor git://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git
git -C $HOME/source/linux.git fetch conor
git -C $HOME/source/linux.git checkout riscv-dt-for-v6.10-take2
git -C $HOME/source/linux.git rebase v6.9-rc7

Patchwork series:

# v2-riscv-defconfig-Enable-StarFive-JH7110-drivers.patch 
# https://patchwork.kernel.org/project/linux-riscv/list/?series=850668
curl https://patchwork.kernel.org/series/850668/mbox/ | git -C $HOME/source/linux.git am

# Refactoring-Microchip-PCIe-driver-and-add-StarFive-PCIe.patch
# https://patchwork.kernel.org/project/linux-riscv/list/?series=839249
curl https://patchwork.kernel.org/series/839249/mbox/ | git -C $HOME/source/linux.git am
# "Patch failed at 0022 riscv: dts: starfive: add PCIe dts configuration for JH7110"
git -C $HOME/source/linux.git am --skip
curl https://freeshell.de/~e/v16-22-22-riscv-dts-starfive-add-PCIe-dts-configuration-for-JH7110-rebase-for-next.patch | git -C $HOME/source/linux.git am

Build:

make O=$HOME/build/linux -C $HOME/source/linux.git defconfig

cd $HOME/build/linux

# Milk-V Mars CM Lite PCIe PHY and proposed PCIe PLDA support from series 839249
$HOME/source/linux.git/scripts/config --module PCIE_STARFIVE_HOST # selects PCIE_PLDA_HOST

# MOTORCOMM YT8531C
$HOME/source/linux.git/scripts/config --module MOTORCOMM_PHY

# BL24c04f 24C04F 21626P
$HOME/source/linux.git/scripts/config --module EEPROM_AT24

# Crypto
$HOME/source/linux.git/scripts/config --enable AMBA_PL08X # dependency of CRYPTO_DEV_JH7110
$HOME/source/linux.git/scripts/config --module CRYPTO_DEV_JH7110 # selects SM3 and CCM hash modules


# misc other options
# make O=$HOME/build/linux -C $HOME/source/linux.git olddefconfig
# $HOME/source/linux.git/scripts/config --enable USB_CDNSP_PCI
# ? $HOME/source/linux.git/scripts/config --enable USB_CDNSP_GADGET
# ? $HOME/source/linux.git/scripts/config --enable USB_CDNSP_HOST
# $HOME/source/linux.git/scripts/config --enable AXP20X_ADC
# $HOME/source/linux.git/scripts/config --enable AXP20X_POWER
# ? $HOME/source/linux.git/scripts/config --enable BATTERY_AXP20X
# $HOME/source/linux.git/scripts/config --enable CHARGER_AXP20X

# Ignored: VIDEO_STARFIVE_CAMSS MAILBOX INPUT_AXP20X_PEK

# $HOME/source/linux.git/scripts/diffconfig .config.old .config

make O=$HOME/build/linux -C $HOME/source/linux.git olddefconfig
make O=$HOME/build/linux -C $HOME/source/linux.git -j4 bindeb-pkg LOCALVERSION=-jh7110 KDEB_PKGVERSION=1

Attached:

linux-image-6.9.0-rc7-jh7110-00036-gd479e01e625a_1_riscv64.deb.gz (14 MiB)

Errata

There is sometimes a race condition possible with serial console and reboot. If needed this can be avoided:
systemctl stop serial-getty@ttyS0 && reboot

How debian-installer handles creating an EFI System Partition seems to not initialize if the partition scheme matches what was already on disk for a pre-existing one, even when the erase data action is used ; workaround if you want to force formatting for correctness is to change the size slightly and then restart the install process after changes are written to disk.

@moroznah
Copy link

I'm just a Gentoo user with no knowledge in embedded whatsoever trying to get something sane onto Mars CM. @eshattow instructions working nicely.
For some reason a very early eMMC board that i have refuses to take SD card in any way so this was done directly on eMMC. Some caveats along the way:

Serial is flaky, tried multiple USB ones and FT232RL sort of worked.
Tio for firmware updates did not work for me, minicom way:
loady
sf probe
ctrl+A S, ymodem, transfer SPL
crc32 $loadaddr $filesize
sf update $loadaddr 0x0 $filesize
ctrl+A S, ymodem, transfer U-BOOT
crc32 $loadaddr $filesize
sf update $loadaddr 0x100000 $filesize

Debian netinst hanged a few times at package installs with CPU soft lockups during untar. Power cycle / repeat.
During install manually created 100MB EFI and whatever ext4 parts, installed grub.
Anyone tried rEFInd on RISC-V?

Postinst to actually boot, since dtb is absent in EFI, used tftp again :
pci enum; nvme scan; mmc rescan
fatload mmc 0:1 ${kernel_addr_r} efi/debian/grubriscv64.efi
setenv tftp_ip 1.2.3.4
dhcp $fdt_addr_r $tftp_ip:/cmlite/jh7110-milkv-mars-cmlite.dtb
bootefi $kernel_addr_r $fdt_addr_r
Install kernel from .deb, copy dtb file to EFI part.

@eshattow
Please comment how to setup u-boot envs permanently to default into grub without fatloading every time, extlinux.conf is missing and not getting what to do from RTFM.
Thanks!

@platima
Copy link
Contributor

platima commented Feb 11, 2024

Please comment how to setup u-boot envs permanently to default into grub

Hi moroznah. Thanks for the comment but this is not the forum for such discussion - here we talk about the performance of the SBC in question and/or benchmark results, if anything. I think ideally though, there should be minimal discussion as these 'Issues' are just a way to collaboratively store result data.

Your best bet may be to reach out to @eshattow directly, else perhaps the uboot forums, Reddit or have a look at the starfive_tech repos.

I know I broke this guideline myself, but that's a lesson learned. Cheers!

@eshattow
Copy link

@moroznah Thanks! Further discussion is welcome on the Matrix group chat https://matrix.to/#/#milkv-mars:matrix.org part of the Milk-V Matrix Space linked at their website.

@platima
Copy link
Contributor

platima commented Feb 11, 2024

@moroznah Thanks! Further discussion is welcome on the Matrix group chat https://matrix.to/#/#milkv-mars:matrix.org part of the Milk-V Matrix Space linked at their website.

Thanks E! Have a great week everyone

@ConchuOD
Copy link

JH7110 CPU MaskROM has a method of accepting XMODEM data over UART to run as SPL directly so don't worry about bricking your Mars CM Lite. The question then is what SPL programs can be used in this way to enact a recovery?

I haven't used that in quite a while with my jh7110 stuff. @xypron shared this with me and I've used it the couple times I have changed the firmware since: https://github.com/xypron/JH71xx-tools

@eshattow
Copy link

JH7110 CPU MaskROM has a method of accepting XMODEM data over UART to run as SPL directly so don't worry about bricking your Mars CM Lite. The question then is what SPL programs can be used in this way to enact a recovery?

I haven't used that in quite a while with my jh7110 stuff. @xypron shared this with me and I've used it the couple times I have changed the firmware since: https://github.com/xypron/JH71xx-tools

That is a serial transfer tool co-dependent on (not a replacement for) the StarFive recovery.bin SPL. It says right in the README.md -r, --recovery <filename> : Bootloader recovery firmware.

@xypron
Copy link

xypron commented Feb 23, 2024

@eshattow I guess https://github.com/starfive-tech/bootloader_recovery is what you are looking for. It produces jh7100_recovery_boot.bin.

For the VisionFive 2 I found it much easier to set the DIP switches to boot from an SD card, flash the SPI flash from U-Boot and then reset the DIP switches.

@eshattow
Copy link

@eshattow I guess https://github.com/starfive-tech/bootloader_recovery is what you are looking for. It produces jh7100_recovery_boot.bin.

For the VisionFive 2 I found it much easier to set the DIP switches to boot from an SD card, flash the SPI flash from U-Boot and then reset the DIP switches.

Is jh7100_recovery_boot.bin valid for JH7110? There is no JH7100 on the MilkV Mars CM.

@shanduur
Copy link

shanduur commented Apr 8, 2024

Hi! Have anyone tried running upstream kernel? Looks like most of the patches are already there for CPU.

@rhinot
Copy link

rhinot commented Apr 11, 2024

@shanduur Just tried booting the upstream 6.7.9 kernel on a working DietPi stock install (which currently is running a patched 6.1.81).

System didn't boot. Nothing even in the kernel logs that I can share to help debug.

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

No branches or pull requests