Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pps: generators: replace copy of pps-gen info struct with const pointer

Some PPS generator drivers may need to retrieve a pointer to their
internal data while executing the PPS generator enable() method.

During the driver registration the pps_gen_device pointer is returned
from the framework, and for that reason, there is difficulty in
getting generator driver data back in the enable function. We won't be
able to use container_of macro as it results in static assert, and we
might end up in using static pointer.

To solve the issue and to get back the generator driver data back, we
should not copy the struct pps_gen_source_info within the struct
pps_gen_device during the registration stage, but simply save the
pointer of the driver one. In this manner, driver may get a pointer
to their internal data as shown below:

struct pps_gen_foo_data_s {
...
struct pps_gen_source_info gen_info;
struct pps_gen_device *pps_gen;
...
};

static int __init pps_gen_foo_init(void)
{
struct pps_gen_foo_data_s *foo;
...
foo->pps_gen = pps_gen_register_source(&foo->gen_info);
...
}

Then, in the enable() method, we can retrieve the pointer to the main
struct by using the code below:

static int pps_gen_foo_enable(struct pps_gen_device *pps_gen, bool enable)
{
struct pps_gen_foo_data_s *foo = container_of(pps_gen->info,
struct pps_gen_foo_data_s, gen_info);
...
}

Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
Tested-by: Subramanian Mohan <subramanian.mohan@intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Subramanian Mohan <subramanian.mohan@intel.com>
Link: https://lore.kernel.org/r/20250219040618.70962-2-subramanian.mohan@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Subramanian Mohan and committed by
Greg Kroah-Hartman
ac9c5170 6aa98263

+14 -15
+1 -2
Documentation/driver-api/pps.rst
··· 206 206 registered in the kernel by defining a struct pps_gen_source_info as 207 207 follows:: 208 208 209 - static struct pps_gen_source_info pps_gen_dummy_info = { 210 - .name = "dummy", 209 + static const struct pps_gen_source_info pps_gen_dummy_info = { 211 210 .use_system_clock = true, 212 211 .get_time = pps_gen_dummy_get_time, 213 212 .enable = pps_gen_dummy_enable,
+1 -1
drivers/pps/generators/pps_gen-dummy.c
··· 61 61 * The PPS info struct 62 62 */ 63 63 64 - static struct pps_gen_source_info pps_gen_dummy_info = { 64 + static const struct pps_gen_source_info pps_gen_dummy_info = { 65 65 .use_system_clock = true, 66 66 .get_time = pps_gen_dummy_get_time, 67 67 .enable = pps_gen_dummy_enable,
+7 -7
drivers/pps/generators/pps_gen.c
··· 66 66 if (ret) 67 67 return -EFAULT; 68 68 69 - ret = pps_gen->info.enable(pps_gen, status); 69 + ret = pps_gen->info->enable(pps_gen, status); 70 70 if (ret) 71 71 return ret; 72 72 pps_gen->enabled = status; ··· 76 76 case PPS_GEN_USESYSTEMCLOCK: 77 77 dev_dbg(pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n"); 78 78 79 - ret = put_user(pps_gen->info.use_system_clock, uiuarg); 79 + ret = put_user(pps_gen->info->use_system_clock, uiuarg); 80 80 if (ret) 81 81 return -EFAULT; 82 82 ··· 175 175 devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id); 176 176 177 177 cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops); 178 - pps_gen->cdev.owner = pps_gen->info.owner; 178 + pps_gen->cdev.owner = pps_gen->info->owner; 179 179 180 180 err = cdev_add(&pps_gen->cdev, devt, 1); 181 181 if (err) { ··· 183 183 MAJOR(pps_gen_devt), pps_gen->id); 184 184 goto free_ida; 185 185 } 186 - pps_gen->dev = device_create(pps_gen_class, pps_gen->info.parent, devt, 187 - pps_gen, "pps-gen%d", pps_gen->id); 186 + pps_gen->dev = device_create(pps_gen_class, pps_gen->info->parent, devt, 187 + pps_gen, "pps-gen%d", pps_gen->id); 188 188 if (IS_ERR(pps_gen->dev)) { 189 189 err = PTR_ERR(pps_gen->dev); 190 190 goto del_cdev; ··· 225 225 * Return: the PPS generator device in case of success, and ERR_PTR(errno) 226 226 * otherwise. 227 227 */ 228 - struct pps_gen_device *pps_gen_register_source(struct pps_gen_source_info *info) 228 + struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info *info) 229 229 { 230 230 struct pps_gen_device *pps_gen; 231 231 int err; ··· 235 235 err = -ENOMEM; 236 236 goto pps_gen_register_source_exit; 237 237 } 238 - pps_gen->info = *info; 238 + pps_gen->info = info; 239 239 pps_gen->enabled = false; 240 240 241 241 init_waitqueue_head(&pps_gen->queue);
+3 -3
drivers/pps/generators/sysfs.c
··· 19 19 { 20 20 struct pps_gen_device *pps_gen = dev_get_drvdata(dev); 21 21 22 - return sysfs_emit(buf, "%d\n", pps_gen->info.use_system_clock); 22 + return sysfs_emit(buf, "%d\n", pps_gen->info->use_system_clock); 23 23 } 24 24 static DEVICE_ATTR_RO(system); 25 25 ··· 30 30 struct timespec64 time; 31 31 int ret; 32 32 33 - ret = pps_gen->info.get_time(pps_gen, &time); 33 + ret = pps_gen->info->get_time(pps_gen, &time); 34 34 if (ret) 35 35 return ret; 36 36 ··· 49 49 if (ret) 50 50 return ret; 51 51 52 - ret = pps_gen->info.enable(pps_gen, status); 52 + ret = pps_gen->info->enable(pps_gen, status); 53 53 if (ret) 54 54 return ret; 55 55 pps_gen->enabled = status;
+2 -2
include/linux/pps_gen_kernel.h
··· 43 43 44 44 /* The main struct */ 45 45 struct pps_gen_device { 46 - struct pps_gen_source_info info; /* PSS generator info */ 46 + const struct pps_gen_source_info *info; /* PSS generator info */ 47 47 bool enabled; /* PSS generator status */ 48 48 49 49 unsigned int event; ··· 70 70 */ 71 71 72 72 extern struct pps_gen_device *pps_gen_register_source( 73 - struct pps_gen_source_info *info); 73 + const struct pps_gen_source_info *info); 74 74 extern void pps_gen_unregister_source(struct pps_gen_device *pps_gen); 75 75 extern void pps_gen_event(struct pps_gen_device *pps_gen, 76 76 unsigned int event, void *data);