1
0

fix(MP/kernel): add mutex

Use only one mutex for regulator part, one for sysfs and one for the temperature. This is the simplest way to be thread safe and avoid concurrency
This commit is contained in:
2026-06-07 14:37:29 +02:00
parent 5f1974da91
commit ca5dd30872
3 changed files with 58 additions and 5 deletions

View File

@@ -3,6 +3,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include "regulator.h" #include "regulator.h"
#include "../sysfs/sysfs.h" #include "../sysfs/sysfs.h"
@@ -14,6 +15,7 @@ static uint32_t current_period = 1000; /* Current blinking period in ms */
static struct task_struct *regulator_thread = NULL; static struct task_struct *regulator_thread = NULL;
static struct regulator_callbacks regulator_cbs = {0}; static struct regulator_callbacks regulator_cbs = {0};
static DEFINE_MUTEX(regulator_lock);
/* --- Sysfs Callbacks --- */ /* --- Sysfs Callbacks --- */
@@ -22,22 +24,33 @@ static uint32_t cb_get_temperature(void) {
} }
static int cb_get_mode(void) { static int cb_get_mode(void) {
return current_mode; int mode;
mutex_lock(&regulator_lock);
mode = current_mode;
mutex_unlock(&regulator_lock);
return mode;
} }
static void cb_set_mode(int mode) { static void cb_set_mode(int mode) {
/* Accept only 0 or 1 as valid modes */ /* Accept only 0 or 1 as valid modes */
if (mode == 0 || mode == 1) { if (mode == 0 || mode == 1) {
mutex_lock(&regulator_lock);
current_mode = mode; current_mode = mode;
mutex_unlock(&regulator_lock);
pr_info("regulator: Mode switched to %s\n", mode ? "Auto" : "Manual"); pr_info("regulator: Mode switched to %s\n", mode ? "Auto" : "Manual");
} }
} }
static uint32_t cb_get_period(void) { static uint32_t cb_get_period(void) {
return current_period; uint32_t period;
mutex_lock(&regulator_lock);
period = current_period;
mutex_unlock(&regulator_lock);
return period;
} }
static void cb_set_period(uint32_t period_ms) { static void cb_set_period(uint32_t period_ms) {
mutex_lock(&regulator_lock);
/* Allow period changes only in Manual mode */ /* Allow period changes only in Manual mode */
if (current_mode == 0) { if (current_mode == 0) {
if (period_ms > 0) { if (period_ms > 0) {
@@ -51,6 +64,7 @@ static void cb_set_period(uint32_t period_ms) {
} else { } else {
pr_warn("regulator: Cannot set period manually in auto mode\n"); pr_warn("regulator: Cannot set period manually in auto mode\n");
} }
mutex_unlock(&regulator_lock);
} }
/* Pack callbacks into the structure expected by sysfs */ /* Pack callbacks into the structure expected by sysfs */
@@ -80,6 +94,7 @@ static void process_auto_mode(void) {
new_period = 50; new_period = 50;
} }
mutex_lock(&regulator_lock);
/* Apply only if the period has changed to avoid unnecessary hardware updates */ /* Apply only if the period has changed to avoid unnecessary hardware updates */
if (new_period != current_period) { if (new_period != current_period) {
current_period = new_period; current_period = new_period;
@@ -87,12 +102,19 @@ static void process_auto_mode(void) {
pr_info("regulator: Auto mode adjusted period to %u ms (Temp: %u C)\n", pr_info("regulator: Auto mode adjusted period to %u ms (Temp: %u C)\n",
current_period, temp_c); current_period, temp_c);
} }
mutex_unlock(&regulator_lock);
} }
/* Background thread checking the temperature periodically */ /* Background thread checking the temperature periodically */
static int regulator_thread_fn(void *data) { static int regulator_thread_fn(void *data) {
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
if (current_mode == 1) { int mode;
mutex_lock(&regulator_lock);
mode = current_mode;
mutex_unlock(&regulator_lock);
if (mode == 1) {
process_auto_mode(); process_auto_mode();
} }
msleep(1000); msleep(1000);

View File

@@ -5,6 +5,7 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include "sysfs.h" #include "sysfs.h"
@@ -13,14 +14,17 @@ static struct device *sysfs_device = NULL;
/* Global static structure to hold the registered callbacks */ /* Global static structure to hold the registered callbacks */
static struct sysfs_callbacks device_cbs = {0}; static struct sysfs_callbacks device_cbs = {0};
static DEFINE_MUTEX(sysfs_lock);
/* Callback triggered on sysfs temperature file read */ /* Callback triggered on sysfs temperature file read */
static ssize_t temperature_show(struct device *dev, struct device_attribute *attr, char *buf) { static ssize_t temperature_show(struct device *dev, struct device_attribute *attr, char *buf) {
uint32_t temp = 0; uint32_t temp = 0;
mutex_lock(&sysfs_lock);
if (device_cbs.get_temperature) { if (device_cbs.get_temperature) {
temp = device_cbs.get_temperature(); temp = device_cbs.get_temperature();
} }
mutex_unlock(&sysfs_lock);
/* Format the temperature and write it to the buffer */ /* Format the temperature and write it to the buffer */
return snprintf(buf, PAGE_SIZE, "%u.%03u\n", temp / 1000, temp % 1000); return snprintf(buf, PAGE_SIZE, "%u.%03u\n", temp / 1000, temp % 1000);
@@ -30,9 +34,11 @@ static ssize_t temperature_show(struct device *dev, struct device_attribute *att
static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) {
int mode = 0; int mode = 0;
mutex_lock(&sysfs_lock);
if (device_cbs.get_mode) { if (device_cbs.get_mode) {
mode = device_cbs.get_mode(); mode = device_cbs.get_mode();
} }
mutex_unlock(&sysfs_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", mode); return snprintf(buf, PAGE_SIZE, "%d\n", mode);
} }
@@ -43,9 +49,11 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr, con
/* Safely convert string from user space to integer */ /* Safely convert string from user space to integer */
if (kstrtoint(buf, 10, &mode) == 0) { if (kstrtoint(buf, 10, &mode) == 0) {
mutex_lock(&sysfs_lock);
if (device_cbs.set_mode) { if (device_cbs.set_mode) {
device_cbs.set_mode(mode); device_cbs.set_mode(mode);
} }
mutex_unlock(&sysfs_lock);
} }
return count; return count;
@@ -55,9 +63,11 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr, con
static ssize_t period_status_show(struct device *dev, struct device_attribute *attr, char *buf) { static ssize_t period_status_show(struct device *dev, struct device_attribute *attr, char *buf) {
uint32_t period = 0; uint32_t period = 0;
mutex_lock(&sysfs_lock);
if (device_cbs.get_period) { if (device_cbs.get_period) {
period = device_cbs.get_period(); period = device_cbs.get_period();
} }
mutex_unlock(&sysfs_lock);
return snprintf(buf, PAGE_SIZE, "%u\n", period); return snprintf(buf, PAGE_SIZE, "%u\n", period);
} }
@@ -67,9 +77,11 @@ static ssize_t period_set_store(struct device *dev, struct device_attribute *att
uint32_t period; uint32_t period;
if (kstrtouint(buf, 10, &period) == 0) { if (kstrtouint(buf, 10, &period) == 0) {
mutex_lock(&sysfs_lock);
if (device_cbs.set_period) { if (device_cbs.set_period) {
device_cbs.set_period(period); device_cbs.set_period(period);
} }
mutex_unlock(&sysfs_lock);
} }
return count; return count;
@@ -97,10 +109,12 @@ static const struct attribute_group regulator_group = {
int temp_regulator_sysfs_init(struct sysfs_callbacks *cbs) { int temp_regulator_sysfs_init(struct sysfs_callbacks *cbs) {
int ret; int ret;
mutex_lock(&sysfs_lock);
/* Save the callbacks provided by the main module */ /* Save the callbacks provided by the main module */
if (cbs) { if (cbs) {
device_cbs = *cbs; device_cbs = *cbs;
} }
mutex_unlock(&sysfs_lock);
/* Create sysfs class */ /* Create sysfs class */
sysfs_class = class_create(THIS_MODULE, "temp_regulator"); sysfs_class = class_create(THIS_MODULE, "temp_regulator");

View File

@@ -4,6 +4,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mutex.h>
#include "temp.h" #include "temp.h"
@@ -13,8 +14,11 @@
static struct resource *temp_res = NULL; static struct resource *temp_res = NULL;
static void __iomem *temp_reg = NULL; static void __iomem *temp_reg = NULL;
static DEFINE_MUTEX(temp_lock);
int temp_init(void) { int temp_init(void) {
mutex_lock(&temp_lock);
/* Request physical memory region */ /* Request physical memory region */
temp_res = request_mem_region(TEMPERATURE_SENSOR_BASE_ADDR, temp_res = request_mem_region(TEMPERATURE_SENSOR_BASE_ADDR,
TEMPERATURE_SENSOR_REG_SIZE, TEMPERATURE_SENSOR_REG_SIZE,
@@ -28,12 +32,17 @@ int temp_init(void) {
if (temp_reg == NULL) { if (temp_reg == NULL) {
pr_err("temp_regulator: Failed to ioremap registers\n"); pr_err("temp_regulator: Failed to ioremap registers\n");
/* Clean up previously requested region */ /* Clean up previously requested region */
release_mem_region(TEMPERATURE_SENSOR_BASE_ADDR, TEMPERATURE_SENSOR_REG_SIZE); if (temp_res) {
temp_res = NULL; release_mem_region(TEMPERATURE_SENSOR_BASE_ADDR, TEMPERATURE_SENSOR_REG_SIZE);
temp_res = NULL;
}
mutex_unlock(&temp_lock);
return -ENOMEM; return -ENOMEM;
} }
pr_info("temp_regulator: Temperature sensor memory successfully mapped\n"); pr_info("temp_regulator: Temperature sensor memory successfully mapped\n");
mutex_unlock(&temp_lock);
return 0; return 0;
} }
@@ -41,8 +50,11 @@ uint32_t read_temp(void) {
uint32_t temperature = 0; uint32_t temperature = 0;
uint32_t raw_val = 0; uint32_t raw_val = 0;
mutex_lock(&temp_lock);
if (temp_reg == NULL) { if (temp_reg == NULL) {
pr_warn("temp_regulator: Cannot read temperature, sensor not initialized\n"); pr_warn("temp_regulator: Cannot read temperature, sensor not initialized\n");
mutex_unlock(&temp_lock);
return 0; return 0;
} }
@@ -58,10 +70,13 @@ uint32_t read_temp(void) {
temperature = -1452 * (int32_t)raw_val / 10 + 259000; temperature = -1452 * (int32_t)raw_val / 10 + 259000;
} }
mutex_unlock(&temp_lock);
return temperature; return temperature;
} }
void temp_exit(void) { void temp_exit(void) {
mutex_lock(&temp_lock);
/* Unmap virtual address space */ /* Unmap virtual address space */
if (temp_reg != NULL) { if (temp_reg != NULL) {
iounmap(temp_reg); iounmap(temp_reg);
@@ -74,5 +89,7 @@ void temp_exit(void) {
temp_res = NULL; temp_res = NULL;
} }
mutex_unlock(&temp_lock);
pr_info("temp_regulator: Temperature sensor resources released\n"); pr_info("temp_regulator: Temperature sensor resources released\n");
} }