cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

convert_drivers_to_kernel_api.rst (7783B)


      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 :)