Reputation: 29
I'm working on a PMBus device driver kernel module. (This is my first kernel module, so please be nice.) I've added a GPIO interrupt handler which just keeps track of the number of edges received on the GPIO pin, and I've added a sysfs entry to display the number of events that have occurred. This functionality works perfectly.
However, within the interrupt handler, I would like to add a sysfs_notify()
call so that user-space code can poll()
the sysfs file that's keeping track of edges. Unfortunately, the poll is not working, and I believe it's because I am feeding the wrong kobject to sysfs_notify()
.
struct tps25990_data {
struct device *dev;
struct pmbus_driver_info info;
...
unsigned int num_gpio_faults;
};
...
static ssize_t num_gpio_faults_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev->parent);
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct tps25990_data *data = to_tps25990_data(info);
return sysfs_emit(buf, "%d\n", data->num_gpio_faults);
}
static DEVICE_ATTR_RO(num_gpio_faults);
static struct attribute *attributes[] = {
&dev_attr_num_gpio_faults.attr,
NULL,
};
static const struct attribute_group attr_group = {
.attrs = attributes,
};
static const struct attribute_group *tps25990_attribute_groups[] = {
&attr_group,
NULL,
};
...
static irqreturn_t efuse_fault_gpio_irq_handler(int irq, void *dev_id){
struct tps25990_data *data = dev_id;
printk(KERN_INFO "Efuse fault detected on gpio%d\n", desc_to_gpio(data->fault_gpio));
data->num_gpio_faults++;
const char *path;
path = kobject_get_path(&data->dev->kobj, GFP_KERNEL);
dev_info(data->dev, "efuse_fault_gpio_irq_handler Path = %s\n", path);
kfree(path);
sysfs_notify(&data->dev->kobj, NULL, "num_gpio_faults");
return IRQ_HANDLED;
}
static int tps25990_probe(struct i2c_client *client)
{
...
struct tps25990_data *data;
struct pmbus_driver_info *info;
...
data = devm_kzalloc(&client->dev, sizeof(struct tps25990_data), GFP_KERNEL);
data->dev = &client->dev;
info = &data->info;
info->groups = tps25990_attribute_groups;
...
data->fault_gpio = devm_gpiod_get_optional(&client->dev, "fault", GPIOD_IN);
if (data->fault_gpio) {
gpiod_set_consumer_name(data->fault_gpio, "EFUSE FAULT");
data->fault_gpio_irq = gpiod_to_irq(data->fault_gpio);
if (data->fault_gpio_irq < 0) {
dev_err(&client->dev, "No corresponding irq for fault-gpio\n");
return data->fault_gpio_irq;
}
ret = irq_set_irq_type(data->fault_gpio_irq, IRQ_TYPE_EDGE_FALLING);
ret = devm_request_threaded_irq(&client->dev,
data->fault_gpio_irq,
NULL,
efuse_fault_gpio_irq_handler,
0,
"efuse fault",
info);
if (ret) {
dev_info(&client->dev, "Failed to request fault-gpio irq (code: %d)\n", ret);
irq_dispose_mapping(data->fault_gpio_irq);
return ret;
}
} else {
dev_info(&client->dev, "No fault-gpio found in device tree\n");
}
data->num_gpio_faults = 0;
ret = pmbus_do_probe(client, info);
...
}
Once this module is running, I can call cat num_gpio_faults
in the appropriate sysfs directory. The correct number of event edges is displayed, and dmesg
shows:
[ 233.630694] hwmon hwmon3: num_gpio_faults_show Path = /devices/platform/soc/fe804000.i2c/i2c-1/i2c-22/22-0046/hwmon/hwmon3
However, when I generate an edge to fire the interrupt, dmesg
shows:
[ 245.874307] Efuse fault detected on gpio579
[ 245.874342] tps25990 22-0046: efuse_fault_gpio_irq_handler Path = /devices/platform/soc/fe804000.i2c/i2c-1/i2c-22/22-0046
So, it appears that whatever struct device
is being fed to the interrupt handler (which is the struct device
contained in the i2c_client
) is different from the struct device
that is fed to my num_gpio_faults_show()
function. The struct device
that is fed to my num_gpio_faults_show()
function appears to have the full path in the kobject
. However, I haven't been able to determine how to get that correct struct device
fed to my interrupt handler in order to have the correct kobject to send with sysfs_notify()
.
I believe that the correct struct device
is the hwmon_dev
item that is within struct pmbus_data
. However, that struct is not exported and not available in my module.
Any suggestions?
I've tried using the i2c_client device but it has the incorrect kobject.
Upvotes: 0
Views: 217
Reputation: 29
Well I've found a solution, but I'm sure it's not an advisable way to do it. I've added this snippet to my probe function. Here I've used sysfs_get_dirent()
to traverse the subdirectories associated with my struct device
. I've added the correct kobject as part of my driver data (data->hwmon_kobj
), and now in my interrupt handler I can call sysfs_notify(data->hwmon_kobj, NULL, "num_gpio_faults")
. This works as intended. I hate this solution because it assumes a priori knowledge of the subdirectory names (here I know that the subdirectory is named ".../hwmon/hwmon3") and it uses the priv
member of the kernfs_node
(which I'm sure is a no-no). Anyone with a better idea? Is there a more acceptable way to recursively search through subdirectories for a kobject?
struct kernfs_node* kn = sysfs_get_dirent(data->dev->kobj.sd, "hwmon");
if (!kn) {
dev_err(data->dev, "Failed to get hwmon kn\n");
} else {
struct kobject *kobj = (struct kobject *)(kn->priv);
if (!kobj) {
dev_err(data->dev, "Failed to get hwmon kobj\n");
} else {
char hwmon_subdir[8];
struct kernfs_node* subdir_kn;
for (int i = 0; i < 100; i++) {
sprintf(hwmon_subdir, "hwmon%d", i);
subdir_kn = sysfs_get_dirent(kobj->sd, hwmon_subdir);
if (subdir_kn)
break;
}
if (!subdir_kn) {
dev_err(data->dev, "Failed to get hmwon subdirectory kn\n");
} else {
data->hwmon_kobj = (struct kobject *)(subdir_kn->priv);
if (!data->hwmon_kobj) {
dev_err(data->dev, "Failed to get hmwon subdirectory kobj\n");
} else {
const char *path = kobject_get_path(data->hwmon_kobj, GFP_KERNEL);
dev_info(data->dev, "hwmon subdirectory path: %s\n", path);
kfree(path);
}
}
}
}
Upvotes: 0