driver-platform-watchdog-develop.md 17.8 KB
Newer Older
A
Annie_wang 已提交
1
# Watchdog
D
duangavin123 已提交
2

A
Annie_wang 已提交
3
## Overview
D
duangavin123 已提交
4

A
Annie_wang 已提交
5
### Function
D
duangavin123 已提交
6

A
Annie_wang 已提交
7
A watchdog, also called a watchdog timer, is a hardware timing device used to facilitate automatic correction of temporary hardware faults or recover from system malfunctions. Generally, it has an input to feed the watchdog and an output to the reset pin of the system. If an error occurs in the main program of the system and the watchdog timer is not cleared in time, the watchdog timer sends a reset signal to restore the system to the normal state.
D
duangavin123 已提交
8

A
Annie_wang 已提交
9
### Basic Concepts
A
Annie_wang 已提交
10

A
Annie_wang 已提交
11
When the system works properly, a signal is output to the watchdog to prevent it from timing out. This operation is called watchdog feeding. If the watchdog is not fed within the specified time, the watchdog times out and a reset signal is sent to the system to reset the system.
A
Annie_wang 已提交
12

A
Annie_wang 已提交
13
### Working Principles
A
Annie_wang 已提交
14

A
Annie_wang 已提交
15
In the Hardware Driver Foundation (HDF), the watchdog module uses the independent service mode (see Figure 1) for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage.
A
Annie_wang 已提交
16

A
Annie_wang 已提交
17
In the independent service mode, the core layer does not publish a service for the upper layer. Therefore, a service must be published for each controller. To achieve this purpose:
D
duangavin123 已提交
18

A
Annie_wang 已提交
19 20
- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services.
- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**.
D
duangavin123 已提交
21

A
Annie_wang 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
The watchdog module is divided into the following layers:

- Interface layer: provides APIs for opening or closing a watchdog, starting or stopping a watchdog, setting or obtaining the watchdog timeout period, and feeding a watchdog
- Core layer: provides the capabilities of adding or removing a watchdog controller and managing watchdog devices. The core layer interacts with the adaptation layer through hook functions.
- Adaptation layer: instantiates the hook functions to implement specific features.

**Figure 1** Independent service mode

![image](figures/independent-service-mode.png "Watchdog independent service mode")

## Development Guidelines

### When to Use

Watchdogs are used to automatically detect the software exceptions that cannot be directly observed and reset the system when an exception is detected. Before using your watchdogs with OpenHarmony, you need to perform watchdog driver adaptation. The following describes how to do it.

### **Available APIs**

To enable the upper layer to successfully operate the watchdog controller by calling the watchdog APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/watchdog/watchdog_core.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.

**WatchdogMethod**:

```c
D
duangavin123 已提交
45
struct WatchdogMethod {
A
Annie_wang 已提交
46 47 48 49 50 51 52 53
    int32_t (*getStatus)(struct WatchdogCntlr *wdt, int32_t *status);
    int32_t (*setTimeout)(struct WatchdogCntlr *wdt, uint32_t seconds);
    int32_t (*getTimeout)(struct WatchdogCntlr *wdt, uint32_t *seconds);
    int32_t (*start)(struct WatchdogCntlr *wdt);
    int32_t (*stop)(struct WatchdogCntlr *wdt);
    int32_t (*feed)(struct WatchdogCntlr *wdt);
    int32_t (*getPriv)(struct WatchdogCntlr *wdt);  // (Optional) If WatchdogCntlr has the priv member, instantiate priv.
    void (*releasePriv)(struct WatchdogCntlr *wdt); // (Optional)
D
duangavin123 已提交
54 55 56
};
```

A
Annie_wang 已提交
57
**Table 1** Hook functions in WatchdogMethod
A
Annie_wang 已提交
58 59 60

| Function| Input Parameter| Output Parameter| Return Value| Description|
| -------- | -------- | -------- | -------- | -------- |
A
Annie_wang 已提交
61 62 63 64 65
| getStatus | **wdt**: structure pointer to the watchdog controller at the core layer.| status: pointer to the watchdog status (opened or closed) obtained. The value is of the int32_t type.| HDF_STATUS| Obtains the watchdog status.|
| setTimeout | **wdt**: structure pointer to the watchdog controller at the core layer.<br>**seconds**: watchdog timeout duration to set.| –| HDF_STATUS| Sets the watchdog timeout duration, in seconds. Ensure that the actual running time of the watchdog complies with the value set.|
| getTimeout  | **wdt**: structure pointer to the watchdog controller at the core layer.                       | **seconds**: pointer to the timeout duration obtained. The value is of the uint32_t type.               | HDF_STATUS| Obtains the watchdog timeout duration.                                          |
| start       | **wdt**: structure pointer to the watchdog controller at the core layer.                       | –                                                          | HDF_STATUS| Starts a watchdog.                                                  |
| stop        | **wdt**: structure pointer to the watchdog controller at the core layer.                       | –                                                          | HDF_STATUS| Stops a watchdog.                                                  |
A
Annie_wang 已提交
66
| feed | **wdt**: structure pointer to the watchdog controller at the core layer.| –| HDF_STATUS| Feeds a watchdog. |
A
Annie_wang 已提交
67 68 69 70
| getPriv | **wdt**: structure pointer to the watchdog controller at the core layer.| –| HDF_STATUS| Obtains the private data of the watchdog driver.|
| releasePriv | **wdt**: structure pointer to the watchdog controller at the core layer.| –| HDF_STATUS| Releases the private data of the watchdog driver.|

### How to Develop
A
Annie_wang 已提交
71

A
Annie_wang 已提交
72 73 74 75 76 77
The watchdog module adaptation procedure is as follows:

1. Instantiate the driver entry.
2. Configure attribute files.
3. Instantiate the watchdog controller object.
4. Debug the driver.
A
Annie_wang 已提交
78

A
Annie_wang 已提交
79
### Example
A
Annie_wang 已提交
80

A
Annie_wang 已提交
81
The following uses the **//device_soc_hisilicon/common/platform/watchdog/watchdog_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the watchdog driver adaptation.
A
Annie_wang 已提交
82 83 84

1. Instantiate the driver entry.

A
Annie_wang 已提交
85 86
    The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF framework, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
    Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
A
Annie_wang 已提交
87

A
Annie_wang 已提交
88
    Watchdog driver entry example:
A
Annie_wang 已提交
89

A
Annie_wang 已提交
90 91 92 93 94 95 96 97 98 99
    ```c
    struct HdfDriverEntry g_watchdogDriverEntry = {
        .moduleVersion = 1,
        .Bind = Hi35xxWatchdogBind,               // See the Bind function.
        .Init = Hi35xxWatchdogInit,               // See the Init function.
        .Release = Hi35xxWatchdogRelease,         // See the Release function.
        .moduleName = "HDF_PLATFORM_WATCHDOG",    // (Mandatory) The value must be the same as that of moduleName in the .hcs file.
    };
    HDF_INIT(g_watchdogDriverEntry);              // Call HDF_INIT to register the driver entry with the HDF.
    ```
A
Annie_wang 已提交
100

A
Annie_wang 已提交
101
2. Configure attribute files.
A
Annie_wang 已提交
102

A
Annie_wang 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
   Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is related to the driver entry registration. The following example uses one watchdog controller as an example. If there are more watchdog controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **watchdog_config.hcs** are closely related to default values or value ranges of the **WatchdogCntlr** members at the core layer.

   - **device_info.hcs** example:

      Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.

      ```c
      root {
          device_info {
              match_attr = "hdf_manager";
              device_watchdog :: device {                                // Device node.
                  device0 :: deviceNode {                                // DeviceNode of the driver.
                      policy = 2;                                        // The value 2 means to publish services for both kernel- and user-mode processes.
                      priority = 20;                                     // Driver startup priority.
                      permission = 0644;                                 // Permission for the device node created.
                      moduleName = "HDF_PLATFORM_WATCHDOG";              // (Mandatory) Driver name, which must be the same as that of moduleName in the driver entry structure.
                      serviceName = "HDF_PLATFORM_WATCHDOG_0";           // (Mandatory) Unique name of the service released by the driver.
                      deviceMatchAttr = "hisilicon_hi35xx_watchdog_0";   // (Mandatory) Controller private data, which must be the same as the value of match_attr in watchdog_config.hcs.
                  } 
              }
          }
      } 
      ```
A
Annie_wang 已提交
126

A
Annie_wang 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
   - **watchdog_config.hcs** example:

      Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/watchdog/watchdog_config.hcs** file. The parameters are as follows:

      ```c
      root {
          platform {
              template watchdog_controller {                     // (Mandatory) Template configuration. If the template is used to configure device node information, the default values in the template will be used for the fields that are not declared for the node.
                  id = 0;                                        // Watchdog ID.
                  match_attr = "";
                  regBase = 0x12050000;                          // (Mandatory) Physical base address used for address mapping.
                  regStep = 0x1000;                              // (Mandatory) Register offset step used for address mapping.
              }
              controller_0x12050000 :: watchdog_controller {     // (Mandatory) Keyword for matching the private data of the device driver.
                  match_attr = "hisilicon_hi35xx_watchdog_0";    // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
              }
                                                                 // Add node information for each watchdog device.
              ...
          }
      }
      ```
A
Annie_wang 已提交
148

A
Annie_wang 已提交
149
      After the **watchdog_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
A
Annie_wang 已提交
150

A
Annie_wang 已提交
151 152
      ```c
      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/watchdog/watchdog_config.hcs" // Relative path of the file.
A
Annie_wang 已提交
153
      ```
A
Annie_wang 已提交
154 155 156 157 158 159 160 161 162 163

3. Instantiate the watchdog controller object.

   Initialize the **WatchdogCntlr** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init** and **Release**) to instantiate **WatchdogMethod** in **WatchdogCntlr** (so that the underlying driver functions can be called).

   - Define a custom structure.

      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **watchdog_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the watchdog ID, to the object at the core layer.

      ```c
A
Annie_wang 已提交
164
      struct Hi35xxWatchdog {
A
Annie_wang 已提交
165 166 167 168 169
          struct WatchdogCntlr wdt;           // (Mandatory) Control object of the core layer. For details, see the following description.
          OsalSpinlock lock;                  // (Mandatory) You need to implement the spinlock for your watchdog.
          volatile unsigned char *regBase;    // (Mandatory) Register base address used for address mapping.
          uint32_t phyBase;                   // (Mandatory) Physical base address used for address mapping.
          uint32_t regStep;                   // (Mandatory) Register offset step used for address mapping.
A
Annie_wang 已提交
170
      };
A
Annie_wang 已提交
171 172 173 174 175 176 177 178

      struct WatchdogCntlr  {                 // WatchdogCntlr is the controller structure at the core layer. The Init function assigns values to WatchdogCntlr.
          struct IDeviceIoService service;    // Driver service.
          struct HdfDeviceObject *device;     // Driver device object.
          OsalSpinlock lock;                  // Spinlock.
          struct WatchdogMethod *ops;         // Hook functions.
          int16_t wdtId;                      // Watchdog ID.
          void *priv;                         // Private data.
A
Annie_wang 已提交
179 180 181
      };
      ```

A
Annie_wang 已提交
182 183 184 185 186 187 188 189 190 191
   - Instantiate **WatchdogMethod** in **WatchdogCntlr**.

      ```c
      static struct WatchdogMethod g_method = {     // Instantiate the hook functions.
          .getStatus = Hi35xxWatchdogGetStatus,     // Obtain the watchdog status.
          .start = Hi35xxWatchdogStart,             // Start the watchdog.
          .stop = Hi35xxWatchdogStop,               // Stop the watchdog.
          .setTimeout = Hi35xxWatchdogSetTimeout,   // Set the watchdog timeout duration.
          .getTimeout = Hi35xxWatchdogGetTimeout,   //Obtain the watchdog timeout duration.
          .feed = Hi35xxWatchdogFeed,               // Feed the watchdog.
A
Annie_wang 已提交
192 193 194
      };
      ```

A
Annie_wang 已提交
195
   - Implement the **Init** and **Bind** functions.
A
Annie_wang 已提交
196 197 198 199 200 201 202

      Input parameter:

      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.

      Return value:

A
Annie_wang 已提交
203 204 205
      **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file.

      **Table 2** Description of HDF_STATUS
A
Annie_wang 已提交
206 207 208

      | Status| Description|
      | -------- | -------- |
A
Annie_wang 已提交
209
      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
A
Annie_wang 已提交
210 211 212 213 214 215 216
      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
      | HDF_ERR_IO | I/O error.|
      | HDF_SUCCESS | Initialization successful.|
      | HDF_FAILURE | Initialization failed.|

      Function description:

A
Annie_wang 已提交
217 218 219
      Initializes the custom structure object and **WatchdogCntlr**, and calls **WatchdogCntlrAdd()** at the core layer to add the watchdog controller.

      ```c
A
Annie_wang 已提交
220
      // Generally, the Init function initializes the members of the Hi35xxWatchdog structure based on the attribute values in **HdfDeviceObject**.
A
Annie_wang 已提交
221
      // In watchdog_hi35xx.c, it is implemented by the Bind function.
A
Annie_wang 已提交
222 223
      static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device)
      {
A
Annie_wang 已提交
224 225
          (void)device;
          return HDF_SUCCESS;
A
Annie_wang 已提交
226
      }
A
Annie_wang 已提交
227

A
Annie_wang 已提交
228 229
      static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device)
      {
A
Annie_wang 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
          int32_t ret;
          struct Hi35xxWatchdog *hwdt = NULL;
          ...
          hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt)); // Allocate memory for the Hi35xxWatchdog structure pointer.
          ...
          hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep);    // Address mapping.
          ...
          hwdt->wdt.priv = (void *)device->property;                    // (Mandatory) Use the device attributes to assign values to privr, but priv is not called later.
                                                                        //If the priv member is required, instantiate getPriv() and releasePriv() of WatchdogMethod.
          hwdt->wdt.ops = &g_method;                                    // (Mandatory) Hook the WatchdogMethod instance.
          hwdt->wdt.device = device;                                    // (Mandatory) Enable conversion between HdfDeviceObject and WatchdogcCntlr.
          ret = WatchdogCntlrAdd(&hwdt->wdt);                           // (Mandatory) Call this function to initialize the core layer structure. The driver can access the platform core layer only after a success signal is returned.
          if (ret != HDF_SUCCESS) {                                     // If the operation fails, remove the mapping and release the resources requested by the Init function.
              OsalIoUnmap((void *)hwdt->regBase);
              OsalMemFree(hwdt);
              return ret;
          }    
          return HDF_SUCCESS;
A
Annie_wang 已提交
248 249
      }
      ```
A
Annie_wang 已提交
250 251

   - Implement the **Release** function.
A
Annie_wang 已提交
252 253 254 255 256 257 258 259 260 261 262

      Input parameter:

      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.

      Return value:

      No value is returned.

      Function description:

A
Annie_wang 已提交
263
      Releases driver resources. This function assigns values to **Release()** in the driver entry structure. When the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources. The **Release()** function must contain the operations for releasing the memory and deleting the controller.
A
Annie_wang 已提交
264

A
Annie_wang 已提交
265
      ```c
A
Annie_wang 已提交
266 267
      static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device)
      {
A
Annie_wang 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
          struct WatchdogCntlr *wdt = NULL;
          struct Hi35xxWatchdog *hwdt = NULL;
          ...
          wdt = WatchdogCntlrFromDevice(device);    // (Mandatory) Obtain WatchdogCntlr through device.
          ...
          if (wdt == NULL) {
              return;
          }
          WatchdogCntlrRemove(wdt);                 // (Mandatory) Call WatchdogCntlrRemove to release the WatchdogCntlr object.
          hwdt = (struct Hi35xxWatchdog *)wdt;      // Convert WatchdogCntlr to Hi35xxWatchdog.
          if (hwdt->regBase != NULL) {              // (Mandatory) Remove the address mapping.
              OsalIoUnmap((void *)hwdt->regBase);
              hwdt->regBase = NULL;
          }
          OsalMemFree(hwdt);                        // (Mandatory) Release the memory occupied by the custom object.
A
Annie_wang 已提交
283 284
      }
      ```
A
Annie_wang 已提交
285 286 287 288

4. Debug the driver.

   (Optional) For new drivers, verify basic functions, for example, check the information returned after the driver is attached and whether data is successfully transmitted.