Linux Audio

Check our new training course

Loading...
v6.13.7
  1=========================================================
  2Converting old watchdog drivers to the watchdog framework
  3=========================================================
  4
  5by Wolfram Sang <wsa@kernel.org>
  6
  7Before the watchdog framework came into the kernel, every driver had to
  8implement the API on its own. Now, as the framework factored out the common
  9components, those drivers can be lightened making it a user of the framework.
 10This document shall guide you for this task. The necessary steps are described
 11as well as things to look out for.
 12
 13
 14Remove the file_operations struct
 15---------------------------------
 16
 17Old drivers define their own file_operations for actions like open(), write(),
 18etc... These are now handled by the framework and just call the driver when
 19needed. So, in general, the 'file_operations' struct and assorted functions can
 20go. Only very few driver-specific details have to be moved to other functions.
 21Here is a overview of the functions and probably needed actions:
 22
 23- open: Everything dealing with resource management (file-open checks, magic
 24  close preparations) can simply go. Device specific stuff needs to go to the
 25  driver specific start-function. Note that for some drivers, the start-function
 26  also serves as the ping-function. If that is the case and you need start/stop
 27  to be balanced (clocks!), you are better off refactoring a separate start-function.
 28
 29- close: Same hints as for open apply.
 30
 31- write: Can simply go, all defined behaviour is taken care of by the framework,
 32  i.e. ping on write and magic char ('V') handling.
 33
 34- ioctl: While the driver is allowed to have extensions to the IOCTL interface,
 35  the most common ones are handled by the framework, supported by some assistance
 36  from the driver:
 37
 38	WDIOC_GETSUPPORT:
 39		Returns the mandatory watchdog_info struct from the driver
 40
 41	WDIOC_GETSTATUS:
 42		Needs the status-callback defined, otherwise returns 0
 43
 44	WDIOC_GETBOOTSTATUS:
 45		Needs the bootstatus member properly set. Make sure it is 0 if you
 46		don't have further support!
 47
 48	WDIOC_SETOPTIONS:
 49		No preparations needed
 50
 51	WDIOC_KEEPALIVE:
 52		If wanted, options in watchdog_info need to have WDIOF_KEEPALIVEPING
 53		set
 54
 55	WDIOC_SETTIMEOUT:
 56		Options in watchdog_info need to have WDIOF_SETTIMEOUT set
 57		and a set_timeout-callback has to be defined. The core will also
 58		do limit-checking, if min_timeout and max_timeout in the watchdog
 59		device are set. All is optional.
 60
 61	WDIOC_GETTIMEOUT:
 62		No preparations needed
 63
 64	WDIOC_GETTIMELEFT:
 65		It needs get_timeleft() callback to be defined. Otherwise it
 66		will return EOPNOTSUPP
 67
 68  Other IOCTLs can be served using the ioctl-callback. Note that this is mainly
 69  intended for porting old drivers; new drivers should not invent private IOCTLs.
 70  Private IOCTLs are processed first. When the callback returns with
 71  -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error
 72  is directly given to the user.
 73
 74Example conversion::
 75
 76  -static const struct file_operations s3c2410wdt_fops = {
 77  -       .owner          = THIS_MODULE,
 
 78  -       .write          = s3c2410wdt_write,
 79  -       .unlocked_ioctl = s3c2410wdt_ioctl,
 80  -       .open           = s3c2410wdt_open,
 81  -       .release        = s3c2410wdt_release,
 82  -};
 83
 84Check the functions for device-specific stuff and keep it for later
 85refactoring. The rest can go.
 86
 87
 88Remove the miscdevice
 89---------------------
 90
 91Since the file_operations are gone now, you can also remove the 'struct
 92miscdevice'. The framework will create it on watchdog_dev_register() called by
 93watchdog_register_device()::
 94
 95  -static struct miscdevice s3c2410wdt_miscdev = {
 96  -       .minor          = WATCHDOG_MINOR,
 97  -       .name           = "watchdog",
 98  -       .fops           = &s3c2410wdt_fops,
 99  -};
100
101
102Remove obsolete includes and defines
103------------------------------------
104
105Because of the simplifications, a few defines are probably unused now. Remove
106them. Includes can be removed, too. For example::
107
108  - #include <linux/fs.h>
109  - #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used)
110  - #include <linux/uaccess.h> (if no custom IOCTLs are used)
111
112
113Add the watchdog operations
114---------------------------
115
116All possible callbacks are defined in 'struct watchdog_ops'. You can find it
117explained in 'watchdog-kernel-api.txt' in this directory. start() and
118owner must be set, the rest are optional. You will easily find corresponding
119functions in the old driver. Note that you will now get a pointer to the
120watchdog_device as a parameter to these functions, so you probably have to
121change the function header. Other changes are most likely not needed, because
122here simply happens the direct hardware access. If you have device-specific
123code left from the above steps, it should be refactored into these callbacks.
124
125Here is a simple example::
126
127  +static struct watchdog_ops s3c2410wdt_ops = {
128  +       .owner = THIS_MODULE,
129  +       .start = s3c2410wdt_start,
130  +       .stop = s3c2410wdt_stop,
131  +       .ping = s3c2410wdt_keepalive,
132  +       .set_timeout = s3c2410wdt_set_heartbeat,
133  +};
134
135A typical function-header change looks like::
136
137  -static void s3c2410wdt_keepalive(void)
138  +static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
139   {
140  ...
141  +
142  +       return 0;
143   }
144
145  ...
146
147  -       s3c2410wdt_keepalive();
148  +       s3c2410wdt_keepalive(&s3c2410_wdd);
149
150
151Add the watchdog device
152-----------------------
153
154Now we need to create a 'struct watchdog_device' and populate it with the
155necessary information for the framework. The struct is also explained in detail
156in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory
157watchdog_info struct and the newly created watchdog_ops. Often, old drivers
158have their own record-keeping for things like bootstatus and timeout using
159static variables. Those have to be converted to use the members in
160watchdog_device. Note that the timeout values are unsigned int. Some drivers
161use signed int, so this has to be converted, too.
162
163Here is a simple example for a watchdog device::
164
165  +static struct watchdog_device s3c2410_wdd = {
166  +       .info = &s3c2410_wdt_ident,
167  +       .ops = &s3c2410wdt_ops,
168  +};
169
170
171Handle the 'nowayout' feature
172-----------------------------
173
174A few drivers use nowayout statically, i.e. there is no module parameter for it
175and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be
176used. This needs to be converted by initializing the status variable of the
177watchdog_device like this::
178
179        .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
180
181Most drivers, however, also allow runtime configuration of nowayout, usually
182by adding a module parameter. The conversion for this would be something like::
183
184	watchdog_set_nowayout(&s3c2410_wdd, nowayout);
185
186The module parameter itself needs to stay, everything else related to nowayout
187can go, though. This will likely be some code in open(), close() or write().
188
189
190Register the watchdog device
191----------------------------
192
193Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev).
194Make sure the return value gets checked and the error message, if present,
195still fits. Also convert the unregister case::
196
197  -       ret = misc_register(&s3c2410wdt_miscdev);
198  +       ret = watchdog_register_device(&s3c2410_wdd);
199
200  ...
201
202  -       misc_deregister(&s3c2410wdt_miscdev);
203  +       watchdog_unregister_device(&s3c2410_wdd);
204
205
206Update the Kconfig-entry
207------------------------
208
209The entry for the driver now needs to select WATCHDOG_CORE:
210
211  +       select WATCHDOG_CORE
212
213
214Create a patch and send it to upstream
215--------------------------------------
216
217Make sure you understood Documentation/process/submitting-patches.rst and send your patch to
218linux-watchdog@vger.kernel.org. We are looking forward to it :)
v6.8
  1=========================================================
  2Converting old watchdog drivers to the watchdog framework
  3=========================================================
  4
  5by Wolfram Sang <wsa@kernel.org>
  6
  7Before the watchdog framework came into the kernel, every driver had to
  8implement the API on its own. Now, as the framework factored out the common
  9components, those drivers can be lightened making it a user of the framework.
 10This document shall guide you for this task. The necessary steps are described
 11as well as things to look out for.
 12
 13
 14Remove the file_operations struct
 15---------------------------------
 16
 17Old drivers define their own file_operations for actions like open(), write(),
 18etc... These are now handled by the framework and just call the driver when
 19needed. So, in general, the 'file_operations' struct and assorted functions can
 20go. Only very few driver-specific details have to be moved to other functions.
 21Here is a overview of the functions and probably needed actions:
 22
 23- open: Everything dealing with resource management (file-open checks, magic
 24  close preparations) can simply go. Device specific stuff needs to go to the
 25  driver specific start-function. Note that for some drivers, the start-function
 26  also serves as the ping-function. If that is the case and you need start/stop
 27  to be balanced (clocks!), you are better off refactoring a separate start-function.
 28
 29- close: Same hints as for open apply.
 30
 31- write: Can simply go, all defined behaviour is taken care of by the framework,
 32  i.e. ping on write and magic char ('V') handling.
 33
 34- ioctl: While the driver is allowed to have extensions to the IOCTL interface,
 35  the most common ones are handled by the framework, supported by some assistance
 36  from the driver:
 37
 38	WDIOC_GETSUPPORT:
 39		Returns the mandatory watchdog_info struct from the driver
 40
 41	WDIOC_GETSTATUS:
 42		Needs the status-callback defined, otherwise returns 0
 43
 44	WDIOC_GETBOOTSTATUS:
 45		Needs the bootstatus member properly set. Make sure it is 0 if you
 46		don't have further support!
 47
 48	WDIOC_SETOPTIONS:
 49		No preparations needed
 50
 51	WDIOC_KEEPALIVE:
 52		If wanted, options in watchdog_info need to have WDIOF_KEEPALIVEPING
 53		set
 54
 55	WDIOC_SETTIMEOUT:
 56		Options in watchdog_info need to have WDIOF_SETTIMEOUT set
 57		and a set_timeout-callback has to be defined. The core will also
 58		do limit-checking, if min_timeout and max_timeout in the watchdog
 59		device are set. All is optional.
 60
 61	WDIOC_GETTIMEOUT:
 62		No preparations needed
 63
 64	WDIOC_GETTIMELEFT:
 65		It needs get_timeleft() callback to be defined. Otherwise it
 66		will return EOPNOTSUPP
 67
 68  Other IOCTLs can be served using the ioctl-callback. Note that this is mainly
 69  intended for porting old drivers; new drivers should not invent private IOCTLs.
 70  Private IOCTLs are processed first. When the callback returns with
 71  -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error
 72  is directly given to the user.
 73
 74Example conversion::
 75
 76  -static const struct file_operations s3c2410wdt_fops = {
 77  -       .owner          = THIS_MODULE,
 78  -       .llseek         = no_llseek,
 79  -       .write          = s3c2410wdt_write,
 80  -       .unlocked_ioctl = s3c2410wdt_ioctl,
 81  -       .open           = s3c2410wdt_open,
 82  -       .release        = s3c2410wdt_release,
 83  -};
 84
 85Check the functions for device-specific stuff and keep it for later
 86refactoring. The rest can go.
 87
 88
 89Remove the miscdevice
 90---------------------
 91
 92Since the file_operations are gone now, you can also remove the 'struct
 93miscdevice'. The framework will create it on watchdog_dev_register() called by
 94watchdog_register_device()::
 95
 96  -static struct miscdevice s3c2410wdt_miscdev = {
 97  -       .minor          = WATCHDOG_MINOR,
 98  -       .name           = "watchdog",
 99  -       .fops           = &s3c2410wdt_fops,
100  -};
101
102
103Remove obsolete includes and defines
104------------------------------------
105
106Because of the simplifications, a few defines are probably unused now. Remove
107them. Includes can be removed, too. For example::
108
109  - #include <linux/fs.h>
110  - #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used)
111  - #include <linux/uaccess.h> (if no custom IOCTLs are used)
112
113
114Add the watchdog operations
115---------------------------
116
117All possible callbacks are defined in 'struct watchdog_ops'. You can find it
118explained in 'watchdog-kernel-api.txt' in this directory. start() and
119owner must be set, the rest are optional. You will easily find corresponding
120functions in the old driver. Note that you will now get a pointer to the
121watchdog_device as a parameter to these functions, so you probably have to
122change the function header. Other changes are most likely not needed, because
123here simply happens the direct hardware access. If you have device-specific
124code left from the above steps, it should be refactored into these callbacks.
125
126Here is a simple example::
127
128  +static struct watchdog_ops s3c2410wdt_ops = {
129  +       .owner = THIS_MODULE,
130  +       .start = s3c2410wdt_start,
131  +       .stop = s3c2410wdt_stop,
132  +       .ping = s3c2410wdt_keepalive,
133  +       .set_timeout = s3c2410wdt_set_heartbeat,
134  +};
135
136A typical function-header change looks like::
137
138  -static void s3c2410wdt_keepalive(void)
139  +static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
140   {
141  ...
142  +
143  +       return 0;
144   }
145
146  ...
147
148  -       s3c2410wdt_keepalive();
149  +       s3c2410wdt_keepalive(&s3c2410_wdd);
150
151
152Add the watchdog device
153-----------------------
154
155Now we need to create a 'struct watchdog_device' and populate it with the
156necessary information for the framework. The struct is also explained in detail
157in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory
158watchdog_info struct and the newly created watchdog_ops. Often, old drivers
159have their own record-keeping for things like bootstatus and timeout using
160static variables. Those have to be converted to use the members in
161watchdog_device. Note that the timeout values are unsigned int. Some drivers
162use signed int, so this has to be converted, too.
163
164Here is a simple example for a watchdog device::
165
166  +static struct watchdog_device s3c2410_wdd = {
167  +       .info = &s3c2410_wdt_ident,
168  +       .ops = &s3c2410wdt_ops,
169  +};
170
171
172Handle the 'nowayout' feature
173-----------------------------
174
175A few drivers use nowayout statically, i.e. there is no module parameter for it
176and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be
177used. This needs to be converted by initializing the status variable of the
178watchdog_device like this::
179
180        .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
181
182Most drivers, however, also allow runtime configuration of nowayout, usually
183by adding a module parameter. The conversion for this would be something like::
184
185	watchdog_set_nowayout(&s3c2410_wdd, nowayout);
186
187The module parameter itself needs to stay, everything else related to nowayout
188can go, though. This will likely be some code in open(), close() or write().
189
190
191Register the watchdog device
192----------------------------
193
194Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev).
195Make sure the return value gets checked and the error message, if present,
196still fits. Also convert the unregister case::
197
198  -       ret = misc_register(&s3c2410wdt_miscdev);
199  +       ret = watchdog_register_device(&s3c2410_wdd);
200
201  ...
202
203  -       misc_deregister(&s3c2410wdt_miscdev);
204  +       watchdog_unregister_device(&s3c2410_wdd);
205
206
207Update the Kconfig-entry
208------------------------
209
210The entry for the driver now needs to select WATCHDOG_CORE:
211
212  +       select WATCHDOG_CORE
213
214
215Create a patch and send it to upstream
216--------------------------------------
217
218Make sure you understood Documentation/process/submitting-patches.rst and send your patch to
219linux-watchdog@vger.kernel.org. We are looking forward to it :)