11 | | = Bus = |
12 | | |
| 24 | |
| 25 | The Driver Manager fills some of the purposes the "The Linux Device Model" fills. |
| 26 | |
| 27 | It is a small and simple manager that connects a driver to a device and a device to driver resources. The |
| 28 | driver is presented an API where it is possible to get the bus frequency, manage interrupt, get base register |
| 29 | addresses, get configuration for a certain hardware device, etc. |
| 30 | |
| 31 | Once a device has been registered by a bus driver the manager tries to find a suitable driver by comparing |
| 32 | the information about the hardware (provided by the bus driver) to the driver hardware support information |
| 33 | (provided by the driver). When a driver is found that can handle the device the device and driver are |
| 34 | "united". The device is put into a list later processed by the driver manager. |
| 35 | |
| 36 | All drivers are registered before starting scanning for devices. |
| 37 | |
| 38 | The driver manager uses the concepts bus, device, driver and driver resources. A bus represents |
| 39 | a device with child devices. A device represents a certain hardware. The topmost device is a bus |
| 40 | device, the root bus device. All devices is connected to the root bus device. |
| 41 | |
| 42 | The root bus device is the first device created during driver manager initialization. It is assigned |
| 43 | a driver, the root bus driver, manually. The root bus driver must be configured by the user or |
| 44 | BSP prior to driver manager initialization. The root bus device is initialized and reports the |
| 45 | available hardware on the bus., once the root bus device is done initializing the driver manager |
| 46 | proceeds to initialize the found devices in a two step process. |
| 47 | |
| 48 | Once a device has been registered by a bus driver the manager tries to find a suitable driver by comparing |
| 49 | the information about the hardware (provided by the bus driver) to the driver hardware support information |
| 50 | (provided by the driver). When a driver is found that can handle the device the device and driver are |
| 51 | "united". The device is put into a list later processed by the driver manager (init1 stage). When the root |
| 52 | bus device driver is done initializing the driver manager proceeds to initialize the found devices in a two |
| 53 | step process. |
| 54 | |
| 55 | All devices are initialized in a two step process, called init1 and init2. Each driver provides two |
| 56 | function pointers init1 and init2 which are called in order. All device's init1 is first called, when |
| 57 | completed the driver manager enter stage two where all devices are called once more, this time |
| 58 | using the init2 function. The initialization process is separated in two stages to make it possible |
| 59 | for drivers to rely on other drivers being initialized. The order in which the devices are initialized |
| 60 | on a bus can not be known (the same order as they are registered in which often depends on how the |
| 61 | hardware is found in the Plug and Play information). |
| 62 | |
| 63 | All drivers that export some functionality to other drivers, for example memory controller drivers, |
| 64 | must initialize their API in stage1 in order to guarantee the service for other drivers when they |
| 65 | enter stage 2. |
| 66 | |
| 67 | All devices and bus devices should be found and registered in stage1. If not, they are called "hotplug" |
| 68 | devices by the driver manager. Hotplugging has currently no special support in the driver manager. |
| 69 | |
| 70 | Below are some concepts described that are used by the manager. |
| 71 | = Bus Driver = |
| 72 | |
| 73 | The Driver Manager needs to be informed about hardware devices present in the system, that is what the bus |
| 74 | driver does. The bus driver reads a hardcoded set up or Plug & Play information and registers devices to |
| 75 | the manager. The bus driver must provide some services in order for the drivers to the found devices to |
| 76 | function properly. The services are implemented by functions that are pointed to by a operations struct |
| 77 | making it possible for the manager driver interface to call the functions. |
| 78 | |
| 79 | The bus driver must be able to unite a hardware device with a driver. |
| 80 | |
| 81 | {{{ |
| 82 | /*! Bus information. Describes a bus. */ |
| 83 | struct rtems_drvmgr_bus_info { |
| 84 | int bus_type; /*!< Type of bus */ |
| 85 | struct rtems_drvmgr_bus_info *next; /*!< Next Bus */ |
| 86 | struct rtems_drvmgr_dev_info *dev; /*!< Bus device, the hardware... */ |
| 87 | void *priv; /*!< Private data structure used by BUS driver */ |
| 88 | struct rtems_drvmgr_dev_info *children; /*!< Hardware devices on this bus */ |
| 89 | struct rtems_drvmgr_bus_ops *ops; /*!< Bus operations supported by this bus driver */ |
| 90 | int dev_cnt; /*!< Number of devices this bus has */ |
| 91 | struct bus_res_node *reslist; /*!< Bus resources, head of a linked list of resources. */ |
| 92 | struct bus_mmap_entry *mmaps; /*!< Memory Map Translation, array of address spaces */ |
| 93 | }; |
| 94 | }}} |
| 95 | = Root bus driver = |
| 96 | |
| 97 | The driver manager needs to know what driver should handle the CPU bus. The root bus driver is |
| 98 | registered separately and before the driver manager is initialized. |
| 101 | Represents a hardware normally found by the bus driver. A device is created and registered by the bus |
| 102 | driver, once registered the driver manager finds the driver that supports the hardware, then a driver |
| 103 | is united with the device. Each device structure has a private pointer that the driver use to access |
| 104 | the information needed by the driver. |
| 105 | |
| 106 | {{{ |
| 107 | /* States of a device */ |
| 108 | #define DEV_STATE_INIT1_DONE 0x00000001 /* Init 1 Stage has been done, not neccessarily successful */ |
| 109 | #define DEV_STATE_INIT2_DONE 0x00000002 /* Init 2 Stage has been done, not neccessarily successful */ |
| 110 | #define DEV_STATE_INIT1_FAILED 0x00000010 /* Init 1 Stage Failed */ |
| 111 | #define DEV_STATE_INIT2_FAILED 0x00000020 /* Init 2 Stage Failed */ |
| 112 | #define DEV_STATE_UNITED 0x00000100 /* Device United with Device Driver */ |
| 113 | #define DEV_STATE_DELETED 0x00000200 /* Device has been deleted (unregistered) */ |
| 114 | |
| 115 | /*! Device information */ |
| 116 | struct rtems_drvmgr_dev_info { |
| 117 | struct rtems_drvmgr_dev_info *next; /*!< Next device */ |
| 118 | struct rtems_drvmgr_dev_info *next_in_bus; /*!< Next device on the same bus */ |
| 119 | struct rtems_drvmgr_dev_info *next_in_drv; /*!< Next device using the same driver */ |
| 120 | |
| 121 | struct rtems_drvmgr_drv_info *drv; /*!< The driver owning this device */ |
| 122 | struct rtems_drvmgr_bus_info *parent; /*!< Bus that this device resides on */ |
| 123 | short minor_drv; /*!< Device number on driver (often minor in filesystem) */ |
| 124 | short minor_bus; /*!< Device number on bus (for device separation) */ |
| 125 | unsigned int state; /*!< State of this device, see DEV_STATE_* */ |
| 126 | char *name; /*!< Name of Device Hardware */ |
| 127 | void *priv; /*!< Pointer to driver private device structure */ |
| 128 | void *businfo; /*!< Host bus specific information */ |
| 129 | struct rtems_drvmgr_bus_info *bus; /*!< Pointer to bus, set only if this is a bus */ |
| 130 | }; |
| 131 | }}} |
17 | | = Bus Driver = |
18 | | |
| 134 | |
| 135 | Driver for a hardware device. It uses the driver manager services provided, which in turn rely on the |
| 136 | bus driver. The driver holds information to identify a hardware device, it tells the driver manager what |
| 137 | kind of bus is supported and perhaps the Plug & Play Vendor and Device ID used to identify certain hardware. |
| 138 | |
| 139 | Drivers are called twice to initialize a hardware device. Init1 and Init2 stages. A delete function may |
| 140 | optionally be defined if the driver can handle removing of hardware. |
| 141 | |
| 142 | {{{ |
| 143 | /*! Driver operations, function pointers. */ |
| 144 | struct rtems_drvmgr_drv_ops { |
| 145 | rtems_status_code (*init1)(struct rtems_drvmgr_dev_info *); /*! Function doing Init Stage 1 of a hardware device */ |
| 146 | rtems_status_code (*init2)(struct rtems_drvmgr_dev_info *); /*! Function doing Init Stage 2 of a hardware device */ |
| 147 | rtems_status_code (*delete)(struct rtems_drvmgr_dev_info *); /*! Function called when device instance is to be removed */ |
| 148 | }; |
| 149 | |
| 150 | /*! Information about a driver used during registration */ |
| 151 | struct rtems_drvmgr_drv_info { |
| 152 | struct rtems_drvmgr_drv_info *next; /*!< Next Driver */ |
| 153 | struct rtems_drvmgr_dev_info *dev; /*!< Devices using this driver */ |
| 154 | |
| 155 | unsigned long long drv_id; /*!< Unique Driver ID */ |
| 156 | char *name; /*!< Name of Driver */ |
| 157 | int bus_type; /*!< Type of Bus this driver supports */ |
| 158 | struct rtems_drvmgr_drv_ops *ops; /*!< Driver operations */ |
| 159 | unsigned int dev_cnt; /*!< Number of devices in dev */ |
| 160 | }; |
| 161 | }}} |
21 | | = Operation = |
22 | | |
| 164 | A driver resource is a resource used by a driver for a certain device instance. The resource may |
| 165 | be integer with value 65 called "numberTxDescriptors". The resources are grouped together in |
| 166 | arrays targeting one device instance. The resources are assigned to one or multiple buses making |
| 167 | it possible for the drivers to find whose hardware device is situated on that very bus. Multiple |
| 168 | hardware devices of the same type is separated by their bus unit number which is always the |
| 169 | same between starts. The number usually comes from the order the device if found in the plug |
| 170 | and play information. Below is a typical bus resource definition grlib_drv_resource configuring |
| 171 | two GRSPW device drivers. The second GRSPW core will have double the amount of descriptors |
| 172 | than the first. |
| 173 | |
| 174 | {{{ |
| 175 | /*** Resource definitions *** |
| 176 | * |
| 177 | * Overview of structures: |
| 178 | * All bus resources entries (bus_res_node) are linked together for a bus (bus_info->reslist). |
| 179 | * One bus resource entry has a pointer to an array of driver resources (drv_res). One driver |
| 180 | * resouces is made out of an array of keys (drv_res_key). All keys belongs to the same driver |
| 181 | * and harwdare device. Each key has a Name, Type ID and Data interpreted differently |
| 182 | * depending on the Type ID (union key_value). |
| 183 | * |
| 184 | */ |
| 185 | |
| 186 | /* Key Data Types */ |
| 187 | #define KEY_TYPE_NONE 0 |
| 188 | #define KEY_TYPE_INT 1 |
| 189 | #define KEY_TYPE_STRING 2 |
| 190 | #define KEY_TYPE_POINTER 3 |
| 191 | |
| 192 | #define KEY_EMPTY {NULL, KEY_TYPE_NONE, {0}} |
| 193 | #define RES_EMPTY {0, 0, NULL} |
| 194 | #define MMAP_EMPTY {0, 0, 0} |
| 195 | |
| 196 | /*! Union of different values */ |
| 197 | union key_value { |
| 198 | unsigned int i; /*!< Key data type UNIGNED INTEGER */ |
| 199 | char *str; /*!< Key data type STRING */ |
| 200 | void *ptr; /*!< Key data type ADDRESS/POINTER */ |
| 201 | }; |
| 202 | |
| 203 | /* One key. Holding information relevant to the driver. */ |
| 204 | struct drv_res_key { |
| 205 | char *key_name; /* Name of key */ |
| 206 | int key_type; /* How to interpret key_value */ |
| 207 | union key_value key_value; /* The value or pointer to the value */ |
| 208 | }; |
| 209 | |
| 210 | /*! Bus resource entry, Driver resources for a certain device instance, containing a number of keys |
| 211 | * Where each key hold the data of interest. |
| 212 | */ |
| 213 | struct drv_res { |
| 214 | unsigned long long drv_id; /*!< Identifies the driver this resource is aiming */ |
| 215 | int minor_bus; /*!< Indentifies a specfic device */ |
| 216 | struct drv_res_key *keys; /*!< First key in key array */ |
| 217 | }; |
| 218 | |
| 219 | /*! Bus resource list node */ |
| 220 | struct bus_res_node { |
| 221 | struct bus_res_node *next; /*!< Next resource node in list */ |
| 222 | struct drv_res *resource; /*!< Array of resources, one per device instance */ |
| 223 | }; |
| 224 | }}} |
| 225 | |
| 226 | {{{ |
| 227 | /* GRSPW0 resources */ |
| 228 | struct drv_res_key grlib_grspw0_res[] = |
| 229 | |
| 230 | { |
| 231 | {"txDesc", KEY_TYPE_INT, {(unsigned int)16}}, |
| 232 | {"rxDesc", KEY_TYPE_INT, {(unsigned int)32}}, |
| 233 | KEY_EMPTY |
| 234 | }; |
| 235 | /* GRSPW1 resources */ |
| 236 | struct drv_res_key grlib_grspw1_res[] = |
| 237 | |
| 238 | { |
| 239 | {"txDesc", KEY_TYPE_INT, {(unsigned int)32}}, |
| 240 | {"rxDesc", KEY_TYPE_INT, {(unsigned int)64}}, |
| 241 | KEY_EMPTY |
| 242 | }; |
| 243 | /* GRLIB Plug & Play bus driver resources */ |
| 244 | struct drv_res grlib_drv_resources[] = |
| 245 | |
| 246 | { |
| 247 | {DRIVER_AMBAPP_GAISLER_GRSPW_ID, 0, &grlib_grspw0_res[0]}, |
| 248 | {DRIVER_AMBAPP_GAISLER_GRSPW_ID, 1, &grlib_grspw1_res[0]}, |
| 249 | RES_EMPTY |
| 250 | }; |
| 251 | }}} |
| 252 | |
| 253 | The driver to which the resources belong is identified by a unique driver id. The driver id must be |
| 254 | unique for the bus type, in this case AMBAPP (AMBA Plug & Play). The device instances are |
| 255 | separated by the bus unit number, second entry in the grlib_drv_resources. |
28 | | - Driver resources per bus. |
| 265 | |
| 266 | The driver manager is configured by selecting drivers used by the driver manager and by |
| 267 | registering a root bus prior to driver manager initialization described in the next section. Drivers |
| 268 | may also be configured by using driver resources, see section "Driver Resource". |
| 269 | |
| 270 | The driver resources are registered different depending on bus driver. |
| 271 | |
| 272 | The root bus device driver is registered by calling root_drv_register, the root bus driver may |
| 273 | provide a function doing this, in that case one must call that function instead. For example |
| 274 | drv_mgr_grlib_init register the GRLIB-AMBA Plug & Play Bus as the root bus driver and also |
| 275 | assigns the driver resources for the root bus. |
| 276 | |
| 277 | The drivers are selected by defining the array drv_mgr_drivers, it contains one function pointer |
| 278 | per driver that is responsible to register one or more drivers. The drv_mgr_drivers can be set up |
| 279 | by defining CONFIGURE_INIT, selecting the appropriate drivers and including |
| 280 | drv_mgr/drvmgr_confdefs.h. This approach is similar to configuring a standard RTEMS project |
| 281 | using rtems/confdefs.h. Below is an example how to select drivers. |
| 282 | |
| 283 | {{{ |
| 284 | #include <rtems.h> |
| 285 | #include <bsp.h> |
| 286 | |
| 287 | #define CONFIGURE_INIT |
| 288 | |
| 289 | /* Standard RTEMS set up */ |
| 290 | #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER |
| 291 | #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER |
| 292 | #define CONFIGURE_RTEMS_INIT_TASKS_TABLE |
| 293 | #define CONFIGURE_MAXIMUM_DRIVERS 32 |
| 294 | #include <rtems/confdefs.h> |
| 295 | |
| 296 | /* Driver manager set up */ |
| 297 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRETH |
| 298 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRSPW |
| 299 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRCAN |
| 300 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_OCCAN |
| 301 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_B1553BRM |
| 302 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_APBUART |
| 303 | #define CONFIGURE_DRIVER_AMBAPP_MCTRL |
| 304 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_PCIF |
| 305 | #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRPCI |
| 306 | #define CONFIGURE_DRIVER_PCI_GR_RASTA_IO |
| 307 | #define CONFIGURE_DRIVER_PCI_GR_RASTA_TMTC |
| 308 | #define CONFIGURE_DRIVER_PCI_GR_701 |
| 309 | #include <drv_mgr/drv_manager_confdefs.h> |
| 310 | }}} |
31 | | = = Driver Interface == |
32 | | |
33 | | = = TODO == |
34 | | |
35 | | |
36 | | === BSP === |
| 313 | The driver manager is initialized by the user calling rtems_drvmgr_init() after the root bus driver |
| 314 | has been registered. After the driver manager has been initialized all devices have been united |
| 315 | with their drivers. The driver are ready for usage. |
| 316 | |
| 317 | The initialization cannot currently be done before the I/O Manager intialization, this is one of the |
| 318 | reasons it is initialized in the Init() task as below. |
| 319 | |
| 320 | /* Initializing Driver Manager */ |
| 321 | printf("Initializing manager\n"); |
| 322 | if ( rtems_drvmgr_init() ) { |
| 323 | printf("Driver manager Failed to initialize\n"); |
| 324 | exit(-1); |
| 325 | } |
| 326 | = Driver Interface = |
| 327 | |
| 328 | The Driver Interface. |
| 329 | |
| 330 | {{{ |
| 331 | /*! Get Device pointer from Driver and Driver minor number |
| 332 | * |
| 333 | * \param drv Driver the device is united with. |
| 334 | * \param minor Driver minor number assigned to device. |
| 335 | * \param pdev Location where the Device point will be stored. |
| 336 | * \return Zero on success. -1 on failure, when device was not found in driver |
| 337 | * device list. |
| 338 | */ |
| 339 | int rtems_drvmgr_get_dev( |
| 340 | struct rtems_drvmgr_drv_info *drv, |
| 341 | int minor, |
| 342 | struct rtems_drvmgr_dev_info **pdev); |
| 343 | |
| 344 | /*! Get Bus frequency in Hertz. Frequency is stored into address of freq_hz. |
| 345 | * |
| 346 | * \param dev The Device to get Bus frequency for. |
| 347 | * \param freq_hz Location where Bus Frequency will be stored. |
| 348 | */ |
| 349 | int rtems_drvmgr_get_freq(struct rtems_drvmgr_dev_info *dev, unsigned int *freq_hz); |
| 350 | |
| 351 | /*! Get device name prefix, this name can be used to register a unique name in the |
| 352 | * filesystem or to get an idea where the device is located. |
| 353 | * |
| 354 | * \param dev The Device to get the device Prefix for. |
| 355 | * \param dev_prefix Location where the prefix will be stored. |
| 356 | */ |
| 357 | int rtems_drvmgr_get_dev_prefix(struct rtems_drvmgr_dev_info *dev, char *dev_prefix); |
| 358 | |
| 359 | /*! Register an interrupt handler. |
| 360 | * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources. |
| 361 | * Normally Index is set to 0 to indicated the first and only IRQ source. |
| 362 | * \param func Interrupt Service Routine. |
| 363 | * \param arg Optional ISR argument. |
| 364 | */ |
| 365 | int rtems_drvmgr_interrupt_register( |
| 366 | struct rtems_drvmgr_dev_info *dev, |
| 367 | int index, |
| 368 | void (*func)(int irq, void *arg), |
| 369 | void *arg); |
| 370 | |
| 371 | /*! Enable (unmask) an interrupt source |
| 372 | * |
| 373 | * \param dev Device to enable interrupt for. |
| 374 | * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources. |
| 375 | * Normally Index is set to 0 to indicated the first and only IRQ source. |
| 376 | */ |
| 377 | int rtems_drvmgr_interrupt_enable(struct rtems_drvmgr_dev_info *dev, int index); |
| 378 | |
| 379 | /*! Disable (mask) an interrupt source |
| 380 | * |
| 381 | * \param dev Device to disable interrupt for. |
| 382 | * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources. |
| 383 | * Normally Index is set to 0 to indicated the first and only IRQ source. |
| 384 | */ |
| 385 | int rtems_drvmgr_interrupt_disable(struct rtems_drvmgr_dev_info *dev, int index); |
| 386 | |
| 387 | /*! Clear (ACK) pending interrupt |
| 388 | * |
| 389 | * \param dev Device to clear interrupt for. |
| 390 | * \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources. |
| 391 | * Normally Index is set to 0 to indicated the first and only IRQ source. |
| 392 | */ |
| 393 | int rtems_drvmgr_interrupt_clear(struct rtems_drvmgr_dev_info *dev, int index); |
| 394 | |
| 395 | /*! Translate address |
| 396 | * 1. From CPU local bus to a remote bus for example a PCI target (from_remote_to_cpu = 0) |
| 397 | * 2. From remote bus to CPU local bus (from_remote_to_cpu = 1) |
| 398 | * |
| 399 | * src_address the address to translate, dst_address is where the translated address is stored. |
| 400 | * |
| 401 | * \param dev Device to translate addresses for. |
| 402 | * \param from_remote_to_cpu Selection tranlation direction. |
| 403 | * \param src_address Address to translate |
| 404 | * \param dst_address Location where translated address is stored. |
| 405 | * |
| 406 | * Returns -1 if unable to translate. If no map is present src_address is translated 1:1 (just copied). |
| 407 | */ |
| 408 | int rtems_drvmgr_mmap_translate( |
| 409 | struct rtems_drvmgr_dev_info *dev, |
| 410 | int from_remote_to_cpu, |
| 411 | void *src_address, |
| 412 | void **dst_address); |
| 413 | }}} |
| 414 | = TODO = |
| 415 | |
| 416 | = BSP = |