Skip to content

Day21 - hwmon Driver Cache Mechanism

๐ŸŽฏ Objective

In Day 20, the driver successfully integrated with the hwmon subsystem.

However, each read operation still triggered an I2C transaction, which is inefficient.

In this lab, we introduce a cache mechanism to:

  • Reduce unnecessary I2C transactions
  • Improve performance
  • Implement a time-based update policy

๐Ÿง  Design Concept

Problem

userspace read โ†’ hwmon โ†’ driver โ†’ I2C read

Every read causes hardware access.


Solution: Add Cache Layer

userspace
   โ†“
hwmon
   โ†“
driver cache   โ† NEW
   โ†“
I2C (only when needed)

๐Ÿงฉ Key Design

Cache Data Structure

struct myi2c_sensor_data {
    struct i2c_client *client;
    struct mutex lock;

    bool initialized;
    long temp_mc_cached;
    unsigned long last_update;
    unsigned int cache_interval_ms;
};

Cache Policy

if (!initialized)
    update
else if (now < last_update + interval)
    use cache
else
    update

Update Flow

update_once()
    โ†“
read raw
    โ†“
convert to milli-degree
    โ†“
store in cache
    โ†“
update timestamp

๐Ÿ”ง Implementation

1. Cache Update Helper

static int myi2c_sensor_update_if_needed(struct myi2c_sensor_data *data)
{
    int ret;
    s16 raw;
    unsigned long interval_jiffies;

    if (!data->initialized)
        goto do_update;

    interval_jiffies = msecs_to_jiffies(data->cache_interval_ms);

    if (time_before(jiffies, data->last_update + interval_jiffies))
        return 0;

do_update:
    ret = myi2c_sensor_update_once(data);
    if (ret < 0)
        return ret;

    ret = myi2c_sensor_read_temp_raw(data, &raw);
    if (ret < 0)
        return ret;

    data->temp_mc_cached = raw * 10;
    data->last_update = jiffies;
    data->initialized = true;

    return 0;
}

2. Modify Read Path

static int myi2c_sensor_read_temp_mc(struct myi2c_sensor_data *data, long *temp_mc)
{
    int ret;

    mutex_lock(&data->lock);

    ret = myi2c_sensor_update_if_needed(data);
    if (ret < 0)
        goto out;

    *temp_mc = data->temp_mc_cached;

out:
    mutex_unlock(&data->lock);
    return ret;
}

โš™๏ธ sysfs Control (Cache Interval)

Show

static ssize_t cache_interval_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
{
    struct myi2c_sensor_data *data = dev_get_drvdata(dev);
    unsigned int interval;

    mutex_lock(&data->lock);
    interval = data->cache_interval_ms;
    mutex_unlock(&data->lock);

    return sysfs_emit(buf, "%u\n", interval);
}

Store

static ssize_t cache_interval_store(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
{
    struct myi2c_sensor_data *data = dev_get_drvdata(dev);
    unsigned long val;

    if (kstrtoul(buf, 0, &val))
        return -EINVAL;

    mutex_lock(&data->lock);
    data->cache_interval_ms = (unsigned int)val;
    mutex_unlock(&data->lock);

    return count;
}

Attribute Registration

static DEVICE_ATTR_RW(cache_interval);

static struct attribute *myi2c_sensor_attrs[] = {
    ...
    &dev_attr_cache_interval.attr,
    NULL,
};

๐Ÿงช Testing

Test Script

./test_cache.sh /sys/class/hwmon/hwmon3

Expected Behavior

Case 1: cache_interval = 0

value changes every read

Case 2: cache_interval = 200 ms

A
A   โ† cache hit
B
B   โ† cache hit
C
C

Case 3: cache_interval = 1000 ms

A
A
A
A
A

๐Ÿง  Key Learning Points

1. Driver Policy vs Mechanism

  • Mechanism โ†’ I2C read
  • Policy โ†’ when to read

2. Cache Responsibility

The hwmon subsystem does NOT handle caching.

๐Ÿ‘‰ Driver must implement it.


3. Performance Trade-off

Mode Behavior
No cache Accurate but slow
Cache Efficient but slightly stale

4. Thread Safety

  • Cache access protected by mutex
  • Prevent race conditions

๐Ÿš€ Result

The driver is now:

  • hwmon-compliant
  • performance-optimized
  • policy-driven
  • closer to production-level design

๐Ÿ“Œ Next Step

  • Background polling (workqueue / timer)
  • Interrupt-driven sensor
  • Multi-channel support
  • Integration with lm-sensors