Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions Runner/suites/Kernel/Baseport/cma/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# CMA (Contiguous Memory Allocator) Enablement Test

## Overview

This test validates CMA (Contiguous Memory Allocator) enablement, configuration, and functionality on Qualcomm platforms. CMA is essential for allocating large contiguous memory blocks required by multimedia devices like cameras, displays, and video encoders.

## What is CMA?

CMA (Contiguous Memory Allocator) is a Linux kernel framework that:
- Reserves a pool of physically contiguous memory at boot time
- Allows normal page allocations from this pool when not in use
- Provides large contiguous allocations when needed by devices
- Critical for DMA operations requiring physically contiguous buffers

## Test Coverage

### 1. CMA Kernel Configuration
- **CONFIG_CMA** - Core CMA support (mandatory)
- **CONFIG_DMA_CMA** - Core CMA support (mandatory)
- **CONFIG_CMA_DEBUG** - Core CMA support (mandatory)
- **CONFIG_CMA_DEBUGFS** - Core CMA support (mandatory)
- **CONFIG_CMA_SIZE_MBYTES** - Default CMA size configuration
- **CONFIG_CMA_SIZE_SEL_MBYTES** - CMA size selection method
- **CONFIG_CMA_AREAS** - Maximum number of CMA areas

### 2. CMA Memory Statistics
- Total CMA memory available
- Free CMA memory
- Used CMA memory
- Usage percentage calculation
- Size validation (minimum 1MB)

### 3. CMA Device Tree Configuration
- CMA size from device tree
- CMA alignment properties
- Reserved memory region enumeration

### 4. CMA Initialization and Runtime
- CMA reservation messages in kernel logs
- CMA allocation/release activity
- Error and warning detection
- Runtime behavior validation

### 5. CMA Sysfs/Debugfs Interface
- CMA debugfs (`/sys/kernel/debug/cma`)
- CMA area enumeration
- Per-area allocation statistics
- CMA statistics in `/proc/vmstat`

## Usage

### Run directly:
```bash
cd /path/to/Runner/suites/Kernel/Baseport/cma
./run.sh
```

### Run via test runner:
```bash
cd /path/to/Runner
./run-test.sh cma
```

## Test Results

Generates:
- `cma.res` - Final result (PASS/FAIL)
- Console output with detailed CMA information

## Prerequisites

### Required:
- `CONFIG_DMA_CMA=y` `CONFIG_CMA=y` `CONFIG_CMA_DEBUG=y` `CONFIG_CMA_DEBUGFS=y` in kernel configuration
- CMA memory reserved (via device tree or kernel command line)

### Optional:
- Debugfs mounted at `/sys/kernel/debug` (for detailed statistics)
- Root or appropriate permissions

## Expected Output

```
[INFO] 1980-01-06 00:18:47 - ================================================================================
[INFO] 1980-01-06 00:18:47 - ============ Starting cma Testcase =======================================
[INFO] 1980-01-06 00:18:47 - ================================================================================
[INFO] 1980-01-06 00:18:47 - === CMA Kernel Configuration Validation ===
[PASS] 1980-01-06 00:18:47 - Kernel config CONFIG_CMA is enabled
[PASS] 1980-01-06 00:18:47 - Kernel config CONFIG_DMA_CMA is enabled
[PASS] 1980-01-06 00:18:47 - Kernel config CONFIG_CMA_DEBUG is enabled
[PASS] 1980-01-06 00:18:47 - Kernel config CONFIG_CMA_DEBUGFS is enabled
[PASS] 1980-01-06 00:18:47 - CMA kernel configuration validated
[INFO] 1980-01-06 00:18:47 - Checking optional CMA configurations...
[FAIL] 1980-01-06 00:18:47 - Kernel config CONFIG_CMA_SIZE_MBYTES is missing or not enabled
[INFO] 1980-01-06 00:18:47 - CONFIG_CMA_SIZE_MBYTES: not set (optional)
[PASS] 1980-01-06 00:18:47 - Kernel config CONFIG_CMA_SIZE_SEL_MBYTES is enabled
[INFO] 1980-01-06 00:18:47 - CONFIG_CMA_SIZE_SEL_MBYTES:
[FAIL] 1980-01-06 00:18:48 - Kernel config CONFIG_CMA_AREAS is missing or not enabled
[INFO] 1980-01-06 00:18:48 - CONFIG_CMA_AREAS: not set (optional)
[INFO] 1980-01-06 00:18:48 - === CMA Memory Statistics ===
[INFO] 1980-01-06 00:18:48 - CMA Memory Statistics:
[INFO] 1980-01-06 00:18:48 - Total: 172 MB (176128 kB)
[INFO] 1980-01-06 00:18:48 - Free: 119 MB (122548 kB)
[INFO] 1980-01-06 00:18:48 - Used: 52 MB (53580 kB)
[INFO] 1980-01-06 00:18:48 - Usage: 30%
[PASS] 1980-01-06 00:18:48 - CMA memory statistics validated
[INFO] 1980-01-06 00:18:48 - Total reserved memory regions: 32
[INFO] 1980-01-06 00:18:48 - === CMA Initialization and Runtime ===
[PASS] 1980-01-06 00:18:48 - CMA initialization messages found in dmesg:
[INFO] 1980-01-06 00:18:48 - [ 17.510276] cma: cma_alloc(cma ffffffc0823f1b38, name: reserved, count 2, align 1)
[INFO] 1980-01-06 00:18:48 - [ 17.924390] cma: cma_alloc(cma ffffffc0823f1b38, name: reserved, count 32, align 5)
[INFO] 1980-01-06 00:18:48 - [ 17.935579] cma: cma_alloc(cma ffffffc0823f1b38, name: reserved, count 128, align 7)
[INFO] 1980-01-06 00:18:48 - [ 18.501219] cma: cma_alloc(cma ffffffc0823f1b38, name: reserved, count 2, align 1)
[INFO] 1980-01-06 00:18:48 - CMA allocation/release activity detected
[INFO] 1980-01-06 00:18:48 - Allocations: 42
[INFO] 1980-01-06 00:18:48 - Releases: 8
[INFO] 1980-01-06 00:18:48 - === CMA Sysfs/Debugfs Interface ===
[INFO] 1980-01-06 00:18:48 - Found CMA debugfs: /sys/kernel/debug/cma
[INFO] 1980-01-06 00:18:48 - CMA area: reserved
[INFO] 1980-01-06 00:18:48 - Total CMA areas: 1
[PASS] 1980-01-06 00:18:48 - CMA statistics in /proc/vmstat:
[INFO] 1980-01-06 00:18:48 - nr_free_cma 30637
[INFO] 1980-01-06 00:18:48 - cma_alloc_success 21
[INFO] 1980-01-06 00:18:48 - cma_alloc_fail 0
[INFO] 1980-01-06 00:18:48 - ================================================================================
[PASS] 1980-01-06 00:18:48 - cma : Test Passed
```

## CMA Configuration Methods

### 1. Device Tree Configuration (Recommended)
```dts
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;

linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x0 0x20000000>; /* 512 MB */
alignment = <0x0 0x00400000>; /* 4 MB */
linux,cma-default;
};
};
```

### 2. Kernel Command Line
```bash
cma=512M
```

### 3. Kernel Config Default
```
CONFIG_CMA_SIZE_MBYTES=512
```



## License

Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
SPDX-License-Identifier: BSD-3-Clause
21 changes: 21 additions & 0 deletions Runner/suites/Kernel/Baseport/cma/cma.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
metadata:
format: Lava-Test Test Definition 1.0
name: cma
description: "CMA (Contiguous Memory Allocator) enablement and functionality validation"
maintainer:
- vnarapar@qti.qualcomm.com
os:
- openembedded
scope:
- functional
devices:
- rb3gen2
- qcs6490
- qcs8300
- qcs9100
- sa8775p

run:
steps:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for repo path before entering into the cma directory. Should be something like

- REPO_PATH="$PWD"
- cd "$REPO_PATH/Runner/suites/Kernel/Baseport/cma"
- ./run.sh
- "$REPO_PATH/Runner/utils/send-to-lava.sh" cma.res

- cd $PWD/suites/Kernel/Baseport/cma
- ./run.sh
188 changes: 188 additions & 0 deletions Runner/suites/Kernel/Baseport/cma/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#!/bin/sh

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause

# Robustly find and source init_env
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
INIT_ENV=""
SEARCH="$SCRIPT_DIR"
while [ "$SEARCH" != "/" ]; do
if [ -f "$SEARCH/init_env" ]; then
INIT_ENV="$SEARCH/init_env"
break
fi
SEARCH=$(dirname "$SEARCH")
done

if [ -z "$INIT_ENV" ]; then
echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
exit 1
fi

if [ -z "$__INIT_ENV_LOADED" ]; then
# shellcheck disable=SC1090
. "$INIT_ENV"
fi

# shellcheck disable=SC1090,SC1091
. "$TOOLS/functestlib.sh"

TESTNAME="cma"
test_path=$(find_test_case_by_name "$TESTNAME")
cd "$test_path" || exit 1
res_file="./$TESTNAME.res"

log_info "================================================================================"
log_info "============ Starting $TESTNAME Testcase ======================================="
log_info "================================================================================"

pass=true

log_info "=== CMA Kernel Configuration Validation ==="

# Core CMA configs
CORE_CMA_CONFIGS="CONFIG_CMA CONFIG_DMA_CMA CONFIG_CMA_DEBUG CONFIG_CMA_DEBUGFS"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now you warn only. But you also fail earlier if CONFIG_CMA_DEBUGFS is missing. That’s okay for “enablement” coverage, but you should also emit a clear reason:

If config says enabled but path missing -> likely debugfs not mounted or permission issue -> WARN + remediation

If config not enabled -> FAIL (enablement missing)

Extension (recommended):

call a helper like ensure_debugfs_mounted (if you have one), or implement minimal:

check mountpoint, try mount if root.


if ! check_kernel_config "$CORE_CMA_CONFIGS"; then
log_fail "CMA kernel configuration not enabled"
pass=false
else
log_pass "CMA kernel configuration validated"
fi

OPTIONAL_CMA_CONFIGS="CONFIG_CMA_SIZE_MBYTES CONFIG_CMA_SIZE_SEL_MBYTES CONFIG_CMA_AREAS"

log_info "Checking optional CMA configurations..."
for cfg in $OPTIONAL_CMA_CONFIGS; do
if check_kernel_config "$cfg" 2>/dev/null; then
value=$(grep "^$cfg=" /proc/config.gz 2>/dev/null | cut -d'=' -f2 || echo "enabled")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But /proc/config.gz is gzipped, grep won’t work unless you use zcat. Also check_kernel_config likely already knows how to read config from /proc/config.gz using zgrep/zcat. So the “value=…” printout is wrong on many targets.

Use get_kernel_config_value "$cfg" helper if you have it (or add one).

Or: zcat /proc/config.gz | grep "^$cfg=".

log_info " $cfg: $value"
else
log_info " $cfg: not set (optional)"
fi
done

log_info "=== CMA Memory Statistics ==="

if [ -f "/proc/meminfo" ]; then
if grep -q "CmaTotal" /proc/meminfo; then
cma_total=$(grep "CmaTotal" /proc/meminfo | awk '{print $2}')
cma_free=$(grep "CmaFree" /proc/meminfo | awk '{print $2}')
cma_used=$((cma_total - cma_free))

# Convert to MB for readability
cma_total_mb=$((cma_total / 1024))
cma_free_mb=$((cma_free / 1024))
cma_used_mb=$((cma_used / 1024))

log_info "CMA Memory Statistics:"
log_info " Total: ${cma_total_mb} MB (${cma_total} kB)"
log_info " Free: ${cma_free_mb} MB (${cma_free} kB)"
log_info " Used: ${cma_used_mb} MB (${cma_used} kB)"

# Calculate usage percentage
if [ "$cma_total" -gt 0 ]; then
usage_percent=$((cma_used * 100 / cma_total))
log_info " Usage: ${usage_percent}%"
fi

if [ "$cma_total" -lt 1024 ]; then
log_fail "CMA total size is very small (< 1 MB)"
pass=false
else
log_pass "CMA memory statistics validated"
fi
else
log_fail "CMA statistics not found in /proc/meminfo"
pass=false
fi
else
log_fail "/proc/meminfo not accessible"
pass=false
fi

if [ -d "/proc/device-tree/reserved-memory" ]; then
region_count=0
for region in /proc/device-tree/reserved-memory/*; do
if [ -d "$region" ]; then
region_count=$((region_count + 1))
fi
done
log_info "Total reserved memory regions: $region_count"
fi

log_info "=== CMA Initialization and Runtime ==="

# Check dmesg for CMA initialization
if dmesg | grep -i -q "cma.*reserved"; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay if you’re only logging, but be careful if later you want to update pass=false inside that loop — it won’t work due to subshell. Right now you set pass=false before the pipe in the warning case, so you’re safe, but keep it in mind.

Use scan_dmesg_errors prefer capturing into a variable/file and then iterating without a pipe if you ever need state changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many kernels print CMA reservation messages in different forms (examples):
cma: Reserved 256 MiB at ...
Reserved memory: created CMA memory pool at ...
OF: reserved mem: initialized node linux,cma...

broaden patterns and be explicit:
cma:.*Reserved
CMA:.*reserved (some arch)
reserved mem.*CMA
linux,cma

log_pass "CMA initialization messages found in dmesg:"

dmesg | grep -i "cma.*reserved" | tail -n 5 | while IFS= read -r line; do
log_info " $line"
done
else
log_fail "No CMA initialization messages found in dmesg"
pass=false
fi

if dmesg | grep -i -q "cma.*alloc\|cma.*release"; then
log_info "CMA allocation/release activity detected"
alloc_count=$(dmesg | grep -i -c "cma.*alloc" || echo 0)
release_count=$(dmesg | grep -i -c "cma.*release" || echo 0)
log_info " Allocations: $alloc_count"
log_info " Releases: $release_count"
fi

if dmesg | grep -i "cma" | grep -i -q "error\|fail\|warn"; then
log_fail "CMA warnings/errors found in dmesg:"
pass=false
dmesg | grep -i "cma" | grep -i "error\|fail\|warn" | tail -n 3 | while IFS= read -r line; do
log_warn " $line"
done
fi

log_info "=== CMA Sysfs/Debugfs Interface ==="

if [ -d "/sys/kernel/debug/cma" ]; then
log_info "Found CMA debugfs: /sys/kernel/debug/cma"

# List CMA areas
if [ -d "/sys/kernel/debug/cma" ]; then
cma_area_count=0
for area in /sys/kernel/debug/cma/*; do
if [ -d "$area" ]; then
area_name=$(basename "$area")
log_info " CMA area: $area_name"
cma_area_count=$((cma_area_count + 1))
fi
done
log_info " Total CMA areas: $cma_area_count"
fi
else
log_warn "CMA debugfs not found (may need debugfs mounted)"
fi

if [ -f "/proc/vmstat" ]; then
if grep -q "cma" /proc/vmstat; then
log_pass "CMA statistics in /proc/vmstat:"
grep "cma" /proc/vmstat | while IFS= read -r line; do
log_info " $line"
done
else
log_fail "CMA statistics not found in /proc/vmstat:"
pass=false
fi
fi

log_info "================================================================================"

if $pass; then
log_pass "$TESTNAME : Test Passed"
echo "$TESTNAME PASS" > "$res_file"
exit 0
else
log_fail "$TESTNAME : Test Failed"
echo "$TESTNAME FAIL" > "$res_file"
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d recommend exit 0 always (and rely on .res)

fi
Loading