Changeset 00aece0 in mainline for uspace/srv/devman/devman.c


Ignore:
Timestamp:
2012-02-18T16:47:38Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4449c6c
Parents:
bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/devman.c

    rbd5f3b7 r00aece0  
    3030 * @{
    3131 */
     32/** @file Device Manager
     33 *
     34 * Locking order:
     35 *   (1) driver_t.driver_mutex
     36 *   (2) dev_tree_t.rwlock
     37 *
     38 * Synchronization:
     39 *    - device_tree.rwlock protects:
     40 *        - tree root, complete tree topology
     41 *        - complete contents of device and function nodes
     42 *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
     43 *      being deallocated
     44 *    - find_xxx() functions increase reference count of returned object
     45 *    - find_xxx_no_lock() do not increase reference count
     46 *
     47 * TODO
     48 *    - Track all steady and transient device/function states
     49 *    - Check states, wait for steady state on certain operations
     50 */
    3251
    3352#include <errno.h>
     
    4362#include "devman.h"
    4463
    45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
     64static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
    4665
    4766/* hash table operations */
     
    406425        }
    407426       
     427        fun_add_ref(fun);
    408428        insert_fun_node(tree, fun, str_dup(""), NULL);
     429       
    409430        match_id_t *id = create_match_id();
    410431        id->id = str_dup("root");
     
    422443        }
    423444       
     445        dev_add_ref(dev);
    424446        insert_dev_node(tree, dev, fun);
    425447       
     
    467489/** Assign a driver to a device.
    468490 *
     491 * @param tree          Device tree
    469492 * @param node          The device's node in the device tree.
    470493 * @param drv           The driver.
    471494 */
    472 void attach_driver(dev_node_t *dev, driver_t *drv)
     495void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
    473496{
    474497        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    476499       
    477500        fibril_mutex_lock(&drv->driver_mutex);
     501        fibril_rwlock_write_lock(&tree->rwlock);
    478502       
    479503        dev->drv = drv;
    480504        list_append(&dev->driver_devices, &drv->devices);
    481505       
     506        fibril_rwlock_write_unlock(&tree->rwlock);
     507        fibril_mutex_unlock(&drv->driver_mutex);
     508}
     509
     510/** Detach driver from device.
     511 *
     512 * @param tree          Device tree
     513 * @param node          The device's node in the device tree.
     514 * @param drv           The driver.
     515 */
     516void detach_driver(dev_tree_t *tree, dev_node_t *dev)
     517{
     518        driver_t *drv = dev->drv;
     519       
     520        assert(drv != NULL);
     521       
     522        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
     523            dev->pfun->pathname, drv->name);
     524       
     525        fibril_mutex_lock(&drv->driver_mutex);
     526        fibril_rwlock_write_lock(&tree->rwlock);
     527       
     528        dev->drv = NULL;
     529        list_remove(&dev->driver_devices);
     530       
     531        fibril_rwlock_write_unlock(&tree->rwlock);
    482532        fibril_mutex_unlock(&drv->driver_mutex);
    483533}
     
    556606        while (link != &driver->devices.head) {
    557607                dev = list_get_instance(link, dev_node_t, driver_devices);
     608                fibril_rwlock_write_lock(&tree->rwlock);
     609               
    558610                if (dev->passed_to_driver) {
     611                        fibril_rwlock_write_unlock(&tree->rwlock);
    559612                        link = link->next;
    560613                        continue;
    561614                }
    562615
    563                 /*
    564                  * We remove the device from the list to allow safe adding
    565                  * of new devices (no one will touch our item this way).
    566                  */
    567                 list_remove(link);
     616                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
     617                    (int)atomic_get(&dev->refcnt));
     618                dev_add_ref(dev);
    568619
    569620                /*
     
    572623                 */
    573624                fibril_mutex_unlock(&driver->driver_mutex);
     625                fibril_rwlock_write_unlock(&tree->rwlock);
    574626
    575627                add_device(driver, dev, tree);
     628
     629                dev_del_ref(dev);
    576630
    577631                /*
     
    580634                 */
    581635                fibril_mutex_lock(&driver->driver_mutex);
    582 
    583                 /*
    584                  * Insert the device back.
    585                  * The order is not relevant here so no harm is done
    586                  * (actually, the order would be preserved in most cases).
    587                  */
    588                 list_append(link, &driver->devices);
    589636
    590637                /*
     
    679726        char *loc_name = NULL;
    680727       
     728        assert(fibril_rwlock_is_locked(&tree->rwlock));
     729       
    681730        asprintf(&loc_name, "%s", fun->pathname);
    682731        if (loc_name == NULL)
     
    726775       
    727776        ipc_call_t answer;
    728         aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
     777        aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
    729778            parent_handle, &answer);
    730779       
     
    751800        default:
    752801                dev->state = DEVICE_INVALID;
     802                break;
    753803        }
    754804       
     
    783833       
    784834        /* Attach the driver to the device. */
    785         attach_driver(dev, drv);
     835        attach_driver(tree, dev, drv);
    786836       
    787837        fibril_mutex_lock(&drv->driver_mutex);
     
    797847                add_device(drv, dev, tree);
    798848       
     849        fibril_mutex_lock(&drv->driver_mutex);
     850        fibril_mutex_unlock(&drv->driver_mutex);
     851
     852        fibril_rwlock_write_lock(&tree->rwlock);
     853        if (dev->pfun != NULL) {
     854                dev->pfun->state = FUN_ON_LINE;
     855        }
     856        fibril_rwlock_write_unlock(&tree->rwlock);
    799857        return true;
     858}
     859
     860int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
     861{
     862        async_exch_t *exch;
     863        sysarg_t retval;
     864        driver_t *drv;
     865        devman_handle_t handle;
     866       
     867        assert(dev != NULL);
     868       
     869        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     870       
     871        fibril_rwlock_read_lock(&tree->rwlock);
     872        drv = dev->drv;
     873        handle = dev->handle;
     874        fibril_rwlock_read_unlock(&tree->rwlock);
     875       
     876        exch = async_exchange_begin(drv->sess);
     877        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
     878        async_exchange_end(exch);
     879       
     880        return retval;
     881}
     882
     883int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
     884{
     885        async_exch_t *exch;
     886        sysarg_t retval;
     887        driver_t *drv;
     888        devman_handle_t handle;
     889       
     890        assert(dev != NULL);
     891       
     892        log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
     893       
     894        fibril_rwlock_read_lock(&tree->rwlock);
     895        drv = dev->drv;
     896        handle = dev->handle;
     897        fibril_rwlock_read_unlock(&tree->rwlock);
     898       
     899        exch = async_exchange_begin(drv->sess);
     900        retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
     901        async_exchange_end(exch);
     902       
     903        return retval;
     904}
     905
     906int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
     907{
     908        async_exch_t *exch;
     909        sysarg_t retval;
     910        driver_t *drv;
     911        devman_handle_t handle;
     912       
     913        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     914
     915        fibril_rwlock_read_lock(&tree->rwlock);
     916       
     917        if (fun->dev == NULL) {
     918                /* XXX root function? */
     919                fibril_rwlock_read_unlock(&tree->rwlock);
     920                return EINVAL;
     921        }
     922       
     923        drv = fun->dev->drv;
     924        handle = fun->handle;
     925        fibril_rwlock_read_unlock(&tree->rwlock);
     926       
     927        exch = async_exchange_begin(drv->sess);
     928        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
     929        loc_exchange_end(exch);
     930       
     931        return retval;
     932}
     933
     934int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
     935{
     936        async_exch_t *exch;
     937        sysarg_t retval;
     938        driver_t *drv;
     939        devman_handle_t handle;
     940       
     941        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     942
     943        fibril_rwlock_read_lock(&tree->rwlock);
     944        if (fun->dev == NULL) {
     945                /* XXX root function? */
     946                fibril_rwlock_read_unlock(&tree->rwlock);
     947                return EINVAL;
     948        }
     949       
     950        drv = fun->dev->drv;
     951        handle = fun->handle;
     952        fibril_rwlock_read_unlock(&tree->rwlock);
     953       
     954        exch = async_exchange_begin(drv->sess);
     955        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
     956        loc_exchange_end(exch);
     957       
     958        return retval;
     959
    800960}
    801961
     
    826986        if (!create_root_nodes(tree))
    827987                return false;
    828 
     988   
    829989        /* Find suitable driver and start it. */
    830         return assign_driver(tree->root_node->child, drivers_list, tree);
     990        dev_node_t *rdev = tree->root_node->child;
     991        dev_add_ref(rdev);
     992        int rc = assign_driver(rdev, drivers_list, tree);
     993        dev_del_ref(rdev);
     994       
     995        return rc;
    831996}
    832997
     
    8391004dev_node_t *create_dev_node(void)
    8401005{
    841         dev_node_t *res = malloc(sizeof(dev_node_t));
    842        
    843         if (res != NULL) {
    844                 memset(res, 0, sizeof(dev_node_t));
    845                 list_initialize(&res->functions);
    846                 link_initialize(&res->driver_devices);
    847                 link_initialize(&res->devman_dev);
    848         }
    849        
    850         return res;
     1006        dev_node_t *dev;
     1007       
     1008        dev = calloc(1, sizeof(dev_node_t));
     1009        if (dev == NULL)
     1010                return NULL;
     1011       
     1012        atomic_set(&dev->refcnt, 0);
     1013        list_initialize(&dev->functions);
     1014        link_initialize(&dev->driver_devices);
     1015        link_initialize(&dev->devman_dev);
     1016       
     1017        return dev;
    8511018}
    8521019
     
    8641031}
    8651032
     1033/** Increase device node reference count.
     1034 *
     1035 * @param dev   Device node
     1036 */
     1037void dev_add_ref(dev_node_t *dev)
     1038{
     1039        atomic_inc(&dev->refcnt);
     1040}
     1041
     1042/** Decrease device node reference count.
     1043 *
     1044 * When the count drops to zero the device node is freed.
     1045 *
     1046 * @param dev   Device node
     1047 */
     1048void dev_del_ref(dev_node_t *dev)
     1049{
     1050        if (atomic_predec(&dev->refcnt) == 0)
     1051                delete_dev_node(dev);
     1052}
     1053
     1054
    8661055/** Find the device node structure of the device witch has the specified handle.
    8671056 *
     
    8781067       
    8791068        link = hash_table_find(&tree->devman_devices, &key);
     1069        if (link == NULL)
     1070                return NULL;
     1071       
    8801072        return hash_table_get_instance(link, dev_node_t, devman_dev);
    8811073}
     
    8931085        fibril_rwlock_read_lock(&tree->rwlock);
    8941086        dev = find_dev_node_no_lock(tree, handle);
     1087        if (dev != NULL)
     1088                dev_add_ref(dev);
     1089       
    8951090        fibril_rwlock_read_unlock(&tree->rwlock);
    8961091       
     
    9201115                    list_get_instance(item, fun_node_t, dev_functions);
    9211116
    922                 if (pos < buf_cnt)
     1117                if (pos < buf_cnt) {
    9231118                        hdl_buf[pos] = fun->handle;
     1119                }
     1120
    9241121                pos++;
    9251122        }
     
    9371134fun_node_t *create_fun_node(void)
    9381135{
    939         fun_node_t *res = malloc(sizeof(fun_node_t));
    940        
    941         if (res != NULL) {
    942                 memset(res, 0, sizeof(fun_node_t));
    943                 link_initialize(&res->dev_functions);
    944                 list_initialize(&res->match_ids.ids);
    945                 link_initialize(&res->devman_fun);
    946                 link_initialize(&res->loc_fun);
    947         }
    948        
    949         return res;
     1136        fun_node_t *fun;
     1137
     1138        fun = calloc(1, sizeof(fun_node_t));
     1139        if (fun == NULL)
     1140                return NULL;
     1141       
     1142        fun->state = FUN_INIT;
     1143        atomic_set(&fun->refcnt, 0);
     1144        link_initialize(&fun->dev_functions);
     1145        list_initialize(&fun->match_ids.ids);
     1146        link_initialize(&fun->devman_fun);
     1147        link_initialize(&fun->loc_fun);
     1148       
     1149        return fun;
    9501150}
    9511151
     
    9651165}
    9661166
     1167/** Increase function node reference count.
     1168 *
     1169 * @param fun   Function node
     1170 */
     1171void fun_add_ref(fun_node_t *fun)
     1172{
     1173        atomic_inc(&fun->refcnt);
     1174}
     1175
     1176/** Decrease function node reference count.
     1177 *
     1178 * When the count drops to zero the function node is freed.
     1179 *
     1180 * @param fun   Function node
     1181 */
     1182void fun_del_ref(fun_node_t *fun)
     1183{
     1184        if (atomic_predec(&fun->refcnt) == 0)
     1185                delete_fun_node(fun);
     1186}
     1187
    9671188/** Find the function node with the specified handle.
    9681189 *
     
    9751196        unsigned long key = handle;
    9761197        link_t *link;
     1198        fun_node_t *fun;
    9771199       
    9781200        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    9821204                return NULL;
    9831205       
    984         return hash_table_get_instance(link, fun_node_t, devman_fun);
     1206        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
     1207       
     1208        return fun;
    9851209}
    9861210
     
    9961220       
    9971221        fibril_rwlock_read_lock(&tree->rwlock);
     1222       
    9981223        fun = find_fun_node_no_lock(tree, handle);
     1224        if (fun != NULL)
     1225                fun_add_ref(fun);
     1226       
    9991227        fibril_rwlock_read_unlock(&tree->rwlock);
    10001228       
     
    10041232/** Create and set device's full path in device tree.
    10051233 *
     1234 * @param tree          Device tree
    10061235 * @param node          The device's device node.
    10071236 * @param parent        The parent device node.
     
    10091238 *                      resources etc.).
    10101239 */
    1011 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
    1012 {
     1240static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
     1241{
     1242        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10131243        assert(fun->name != NULL);
    10141244       
     
    10371267 *
    10381268 * @param tree          The device tree.
    1039  * @param node          The newly added device node.
    1040  * @param dev_name      The name of the newly added device.
    1041  * @param parent        The parent device node.
     1269 * @param dev           The newly added device node.
     1270 * @param pfun          The parent function node.
    10421271 *
    10431272 * @return              True on success, false otherwise (insufficient resources
     
    10461275bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    10471276{
    1048         assert(dev != NULL);
    1049         assert(tree != NULL);
    10501277        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10511278       
     
    10651292}
    10661293
     1294/** Remove device from device tree.
     1295 *
     1296 * @param tree          Device tree
     1297 * @param dev           Device node
     1298 */
     1299void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
     1300{
     1301        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1302       
     1303        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
     1304       
     1305        /* Remove node from the handle-to-node map. */
     1306        unsigned long key = dev->handle;
     1307        hash_table_remove(&tree->devman_devices, &key, 1);
     1308       
     1309        /* Unlink from parent function. */
     1310        dev->pfun->child = NULL;
     1311        dev->pfun = NULL;
     1312       
     1313        dev->state = DEVICE_REMOVED;
     1314}
     1315
     1316
    10671317/** Insert new function into device tree.
    10681318 *
    10691319 * @param tree          The device tree.
    1070  * @param node          The newly added function node.
    1071  * @param dev_name      The name of the newly added function.
    1072  * @param parent        Owning device node.
     1320 * @param fun           The newly added function node.
     1321 * @param fun_name      The name of the newly added function.
     1322 * @param dev           Owning device node.
    10731323 *
    10741324 * @return              True on success, false otherwise (insufficient resources
     
    10801330        fun_node_t *pfun;
    10811331       
    1082         assert(fun != NULL);
    1083         assert(tree != NULL);
    10841332        assert(fun_name != NULL);
    10851333        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    10921340       
    10931341        fun->name = fun_name;
    1094         if (!set_fun_path(fun, pfun)) {
     1342        if (!set_fun_path(tree, fun, pfun)) {
    10951343                return false;
    10961344        }
     
    11161364void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    11171365{
    1118         assert(tree != NULL);
    1119         assert(fun != NULL);
    11201366        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11211367       
     
    11271373        if (fun->dev != NULL)
    11281374                list_remove(&fun->dev_functions);
     1375       
     1376        fun->dev = NULL;
     1377        fun->state = FUN_REMOVED;
    11291378}
    11301379
     
    11481397       
    11491398        fun_node_t *fun = tree->root_node;
     1399        fun_add_ref(fun);
    11501400        /*
    11511401         * Relative path to the function from its parent (but with '/' at the
     
    11651415                }
    11661416               
    1167                 fun = find_node_child(fun, rel_path + 1);
     1417                fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
     1418                fun_del_ref(fun);
     1419                fun = cfun;
    11681420               
    11691421                if (cont) {
     
    11831435 * Device tree rwlock should be held at least for reading.
    11841436 *
     1437 * @param tree Device tree
    11851438 * @param dev Device the function belongs to.
    11861439 * @param name Function name (not path).
     
    11881441 * @retval NULL No function with given name.
    11891442 */
    1190 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
    1191 {
    1192         assert(dev != NULL);
     1443fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
     1444    const char *name)
     1445{
    11931446        assert(name != NULL);
     1447        assert(fibril_rwlock_is_locked(&tree->rwlock));
    11941448
    11951449        fun_node_t *fun;
     
    11981452                fun = list_get_instance(link, fun_node_t, dev_functions);
    11991453
    1200                 if (str_cmp(name, fun->name) == 0)
     1454                if (str_cmp(name, fun->name) == 0) {
     1455                        fun_add_ref(fun);
    12011456                        return fun;
     1457                }
    12021458        }
    12031459
     
    12091465 * Device tree rwlock should be held at least for reading.
    12101466 *
     1467 * @param tree          Device tree
    12111468 * @param parent        The parent function node.
    12121469 * @param name          The name of the child function.
    12131470 * @return              The child function node.
    12141471 */
    1215 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
    1216 {
    1217         return find_fun_node_in_device(pfun->child, name);
     1472static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
     1473    const char *name)
     1474{
     1475        return find_fun_node_in_device(tree, pfun->child, name);
    12181476}
    12191477
     
    12281486        fibril_rwlock_read_lock(&tree->rwlock);
    12291487        link = hash_table_find(&tree->loc_functions, &key);
    1230         if (link != NULL)
     1488        if (link != NULL) {
    12311489                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
     1490                fun_add_ref(fun);
     1491        }
    12321492        fibril_rwlock_read_unlock(&tree->rwlock);
    12331493       
     
    12371497void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    12381498{
     1499        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1500       
    12391501        unsigned long key = (unsigned long) fun->service_id;
    1240         fibril_rwlock_write_lock(&tree->rwlock);
    12411502        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
    1242         fibril_rwlock_write_unlock(&tree->rwlock);
    12431503}
    12441504
Note: See TracChangeset for help on using the changeset viewer.