Skip to content

Commit 5c83407

Browse files
committed
On the 512M Pi's, we really should not use cma-256 as that's half the ram. Detect at first boot and flip to cma-128.
1 parent 5dd1962 commit 5c83407

1 file changed

Lines changed: 90 additions & 0 deletions

File tree

src/boot/FPPINIT_Config.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
#include <chrono>
1414
#include "fpp-json.h"
15+
#include <cctype>
1516
#include <cstdio>
17+
#include <cstdlib>
1618
#include <cstring>
1719
#include <fcntl.h>
1820
#include <filesystem>
@@ -935,6 +937,93 @@ void startDiskSwap() {
935937
"| while read -r dev; do /sbin/swapon \"$dev\" 2>/dev/null || true; done");
936938
}
937939

940+
#ifdef PLATFORM_PI
941+
// Shrink an oversized vc4-KMS CMA pool on boards that cannot afford it.
942+
//
943+
// The image ships "dtoverlay=vc4-kms-v3d,cma-256" for every Pi (FPP_Install.sh
944+
// adds it to cap the Pi4's 512MB firmware default -- issue #2679). But the
945+
// overlay's own README documents cma-256, and everything above cma-128, as
946+
// "needs 1GB", and the firmware does NOT clamp it: a 512MB Pi Zero 2 W really
947+
// comes up with CmaTotal 262144 kB. That is half the board handed to a GPU pool
948+
// on a headless controller, and it is enough to break a source rebuild -- it
949+
// leaves ~163MB usable, well under what cc1plus needs.
950+
//
951+
// So cap at cma-128, the largest size the overlay does not gate behind 1GB.
952+
// FPP's real DMA needs are far below that: the DPI envelope declared below is
953+
// 1920x997 RGB888, about 7.6MB.
954+
//
955+
// Only ever REDUCE: a deliberate smaller override (cma-64) is left alone, since
956+
// raising it would defeat the purpose. Rewrites `content` in place and sets
957+
// `changed` so the caller's existing reboot handles it; comparing before writing
958+
// keeps it idempotent, so it fires once and never loops.
959+
// MemTotal counts the CMA reservation, so it is the board's usable total, not
960+
// its marketing size: a 512MB board reports ~425-500MB, a 1GB board ~900MB+.
961+
// 700MB separates them with room on both sides.
962+
static constexpr long CMA_ONE_GB_BOARD_KB = 700000;
963+
static constexpr int CMA_MAX_UNDER_1GB = 128;
964+
965+
// Pure half: no file I/O, so it can be lifted out between the markers below and
966+
// exercised directly against sample config.txt text. Edits `content` in place
967+
// and returns true if it changed anything.
968+
// --- BEGIN capVC4CMALine ---
969+
static bool capVC4CMALine(std::string& content, long memKB) {
970+
if (memKB <= 0 || memKB >= CMA_ONE_GB_BOARD_KB) {
971+
return false;
972+
}
973+
// Match the overlay line itself, never a commented-out or indented copy.
974+
// Covers both the generic overlay and the -pi5 variant.
975+
size_t vidx = content.find("dtoverlay=vc4-kms-v3d");
976+
while (vidx != std::string::npos && vidx != 0 && content[vidx - 1] != '\n') {
977+
vidx = content.find("dtoverlay=vc4-kms-v3d", vidx + 1);
978+
}
979+
if (vidx == std::string::npos) {
980+
return false;
981+
}
982+
size_t eol = content.find("\n", vidx);
983+
if (eol == std::string::npos) {
984+
eol = content.size();
985+
}
986+
std::string line = content.substr(vidx, eol - vidx);
987+
988+
size_t cidx = line.find("cma-");
989+
if (cidx == std::string::npos) {
990+
return false;
991+
}
992+
size_t dstart = cidx + strlen("cma-");
993+
size_t dend = dstart;
994+
while (dend < line.size() && isdigit(static_cast<unsigned char>(line[dend]))) {
995+
dend++;
996+
}
997+
if (dend == dstart) {
998+
// "cma-size" (a raw byte count) or some other spelling -- leave it be.
999+
return false;
1000+
}
1001+
int current = static_cast<int>(strtol(line.c_str() + dstart, nullptr, 10));
1002+
if (current <= CMA_MAX_UNDER_1GB) {
1003+
return false;
1004+
}
1005+
line.replace(cidx, dend - cidx, "cma-" + std::to_string(CMA_MAX_UNDER_1GB));
1006+
printf("FPP - %ldkB board: capping vc4 CMA at %dMB (was %dMB)\n",
1007+
memKB, CMA_MAX_UNDER_1GB, current);
1008+
content.replace(vidx, eol - vidx, line);
1009+
return true;
1010+
}
1011+
// --- END capVC4CMALine ---
1012+
1013+
static void capVC4CMAForBoard(std::string& content, bool& changed) {
1014+
std::string meminfo = GetFileContents("/proc/meminfo");
1015+
size_t midx = meminfo.find("MemTotal:");
1016+
if (midx == std::string::npos) {
1017+
return;
1018+
}
1019+
long memKB = strtol(meminfo.c_str() + midx + strlen("MemTotal:"), nullptr, 10);
1020+
if (capVC4CMALine(content, memKB)) {
1021+
PutFileContents("/boot/firmware/config.txt", content);
1022+
changed = true;
1023+
}
1024+
}
1025+
#endif
1026+
9381027
void setupChannelOutputs() {
9391028
#ifdef PLATFORM_PI
9401029
bool hasDPI = false;
@@ -1008,6 +1097,7 @@ void setupChannelOutputs() {
10081097
exec("modprobe snd_usb_audio");
10091098
}
10101099
std::string content = GetFileContents("/boot/firmware/config.txt");
1100+
capVC4CMAForBoard(content, changed);
10111101
size_t idx = content.find("dtoverlay=vc4-kms-dpi-fpp");
10121102
std::string origLine = "";
10131103
if (idx != std::string::npos) {

0 commit comments

Comments
 (0)