Changeset 1a5b252 in mainline for uspace/srv


Ignore:
Timestamp:
2011-08-21T11:54:15Z (14 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8cc4ddb
Parents:
e64df9a
Message:

DDF support for function offlining and onlining. This allows
(anticipated) hot removal — support needs to be added in individual
drivers, currently there is support in test1 and partially in rootvirt.
Surprise removal is not supported. TODO synchronization.

Location:
uspace/srv/devman
Files:
3 edited

Legend:

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

    re64df9a r1a5b252  
    483483}
    484484
     485/** Detach driver from device.
     486 *
     487 * @param node          The device's node in the device tree.
     488 * @param drv           The driver.
     489 */
     490void detach_driver(dev_node_t *dev)
     491{
     492        /* XXX need lock on dev */
     493        driver_t *drv = dev->drv;
     494       
     495        assert(drv != NULL);
     496        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
     497            dev->pfun->pathname, drv->name);
     498       
     499        fibril_mutex_lock(&drv->driver_mutex);
     500       
     501        dev->drv = NULL;
     502        list_remove(&dev->driver_devices);
     503       
     504        fibril_mutex_unlock(&drv->driver_mutex);
     505}
     506
    485507/** Start a driver
    486508 *
     
    726748       
    727749        ipc_call_t answer;
    728         aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
     750        aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
    729751            parent_handle, &answer);
    730752       
     
    800822}
    801823
     824int driver_dev_remove(dev_node_t *dev)
     825{
     826        async_exch_t *exch;
     827        sysarg_t retval;
     828        driver_t *drv;
     829       
     830        assert(dev != NULL);
     831        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     832        drv = dev->drv;
     833       
     834        exch = async_exchange_begin(drv->sess);
     835        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);
     836        async_exchange_end(exch);
     837       
     838        return retval;
     839
     840}
     841
     842int driver_fun_online(fun_node_t *fun)
     843{
     844        async_exch_t *exch;
     845        sysarg_t retval;
     846        driver_t *drv;
     847       
     848        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     849        if (fun->dev == NULL) {
     850                /* XXX root function? */
     851                return EINVAL;
     852        }
     853       
     854        drv = fun->dev->drv;
     855       
     856        exch = async_exchange_begin(drv->sess);
     857        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);
     858        loc_exchange_end(exch);
     859       
     860        return retval;
     861}
     862
     863int driver_fun_offline(fun_node_t *fun)
     864{
     865        async_exch_t *exch;
     866        sysarg_t retval;
     867        driver_t *drv;
     868       
     869        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     870        if (fun->dev == NULL) {
     871                /* XXX root function? */
     872                return EINVAL;
     873        }
     874       
     875        drv = fun->dev->drv;
     876       
     877        exch = async_exchange_begin(drv->sess);
     878        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);
     879        loc_exchange_end(exch);
     880       
     881        return retval;
     882
     883}
     884
    802885/** Initialize the device tree.
    803886 *
     
    10651148}
    10661149
     1150/** Remove device from device tree.
     1151 *
     1152 * @param tree          Device tree
     1153 * @param dev           Device node
     1154 */
     1155void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
     1156{
     1157        assert(tree != NULL);
     1158        assert(dev != NULL);
     1159        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1160       
     1161        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
     1162       
     1163        /* Remove node from the handle-to-node map. */
     1164        unsigned long key = dev->handle;
     1165        hash_table_remove(&tree->devman_devices, &key, 1);
     1166       
     1167        /* Unlink from parent function. */
     1168        dev->pfun->child = NULL;
     1169        dev->pfun = NULL;
     1170}
     1171
     1172
    10671173/** Insert new function into device tree.
    10681174 *
     
    11271233        if (fun->dev != NULL)
    11281234                list_remove(&fun->dev_functions);
     1235       
     1236        fun->dev = NULL;
    11291237}
    11301238
  • uspace/srv/devman/devman.h

    re64df9a r1a5b252  
    240240extern void add_driver(driver_list_t *, driver_t *);
    241241extern void attach_driver(dev_node_t *, driver_t *);
     242extern void detach_driver(dev_node_t *);
    242243extern void add_device(driver_t *, dev_node_t *, dev_tree_t *);
    243244extern bool start_driver(driver_t *);
     245extern int driver_dev_remove(dev_node_t *);
     246extern int driver_fun_online(fun_node_t *);
     247extern int driver_fun_offline(fun_node_t *);
    244248
    245249extern driver_t *find_driver(driver_list_t *, const char *);
     
    274278extern bool create_root_nodes(dev_tree_t *);
    275279extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *);
     280extern void remove_dev_node(dev_tree_t *, dev_node_t *);
    276281extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *);
    277282extern void remove_fun_node(dev_tree_t *, fun_node_t *);
  • uspace/srv/devman/main.c

    re64df9a r1a5b252  
    237237}
    238238
    239 /** Handle function registration.
    240  *
    241  * Child devices are registered by their parent's device driver.
    242  */
    243 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    244 {
    245         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    246         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    247         sysarg_t match_count = IPC_GET_ARG3(*call);
    248         dev_tree_t *tree = &device_tree;
    249        
    250         fibril_rwlock_write_lock(&tree->rwlock);
    251 
    252         dev_node_t *dev = NULL;
    253         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
    254        
    255         if (pdev == NULL) {
    256                 fibril_rwlock_write_unlock(&tree->rwlock);
    257                 async_answer_0(callid, ENOENT);
    258                 return;
    259         }
    260        
    261         if (ftype != fun_inner && ftype != fun_exposed) {
    262                 /* Unknown function type */
    263                 log_msg(LVL_ERROR,
    264                     "Unknown function type %d provided by driver.",
    265                     (int) ftype);
    266 
    267                 fibril_rwlock_write_unlock(&tree->rwlock);
    268                 async_answer_0(callid, EINVAL);
    269                 return;
    270         }
    271        
    272         char *fun_name = NULL;
    273         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    274         if (rc != EOK) {
    275                 fibril_rwlock_write_unlock(&tree->rwlock);
    276                 async_answer_0(callid, rc);
    277                 return;
    278         }
    279        
    280         /* Check that function with same name is not there already. */
    281         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
    282                 fibril_rwlock_write_unlock(&tree->rwlock);
    283                 async_answer_0(callid, EEXISTS);
    284                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    285                     fun_name);
    286                 free(fun_name);
    287                 return;
    288         }
    289        
    290         fun_node_t *fun = create_fun_node();
    291         fun->ftype = ftype;
    292        
    293         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    294                 fibril_rwlock_write_unlock(&tree->rwlock);
    295                 delete_fun_node(fun);
    296                 async_answer_0(callid, ENOMEM);
    297                 return;
    298         }
    299 
    300         if (ftype == fun_inner) {
     239static int online_function(fun_node_t *fun)
     240{
     241        dev_node_t *dev;
     242       
     243        fibril_rwlock_write_lock(&device_tree.rwlock);
     244       
     245        if (fun->ftype == fun_inner) {
    301246                dev = create_dev_node();
    302247                if (dev == NULL) {
    303                         fibril_rwlock_write_unlock(&tree->rwlock);
     248                        fibril_rwlock_write_unlock(&device_tree.rwlock);
    304249                        delete_fun_node(fun);
    305                         async_answer_0(callid, ENOMEM);
    306                         return;
     250                        return ENOMEM;
    307251                }
    308252
    309                 insert_dev_node(tree, dev, fun);
    310         }
    311 
    312         fibril_rwlock_write_unlock(&tree->rwlock);
     253                insert_dev_node(&device_tree, dev, fun);
     254        }
     255       
     256        fibril_rwlock_write_unlock(&device_tree.rwlock);
    313257       
    314258        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    315259       
    316         devman_receive_match_ids(match_count, &fun->match_ids);
    317 
    318         if (ftype == fun_inner) {
     260        if (fun->ftype == fun_inner) {
     261                dev = fun->child;
    319262                assert(dev != NULL);
     263               
    320264                /*
    321265                 * Try to find a suitable driver and assign it to the device.  We do
     
    336280                }
    337281        } else {
    338                 loc_register_tree_function(fun, tree);
     282                loc_register_tree_function(fun, &device_tree);
     283        }
     284       
     285        return EOK;
     286}
     287
     288static int offline_function(fun_node_t *fun)
     289{
     290        int rc;
     291       
     292        if (fun->ftype == fun_inner) {
     293                printf("devman_drv_fun_offline(): %p is inner fun, removing "
     294                    "child dev.\n", fun);
     295                if (fun->child != NULL) {
     296                        dev_node_t *dev = fun->child;
     297                       
     298                        rc = driver_dev_remove(dev);
     299                        if (rc != EOK) {
     300                                return ENOTSUP;
     301                        }
     302                        detach_driver(dev);
     303                        fibril_rwlock_write_lock(&device_tree.rwlock);
     304                        remove_dev_node(&device_tree, dev);
     305                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     306                        delete_dev_node(dev);
     307                }
     308        } else {
     309                /* Unregister from location service */
     310                rc = loc_service_unregister(fun->service_id);
     311                if (rc != EOK) {
     312                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
     313                        return EIO;
     314                }
     315               
     316                fun->service_id = 0;
     317        }
     318       
     319        return EOK;
     320}
     321
     322/** Handle function registration.
     323 *
     324 * Child devices are registered by their parent's device driver.
     325 */
     326static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     327{
     328        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     329        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     330        sysarg_t match_count = IPC_GET_ARG3(*call);
     331        dev_tree_t *tree = &device_tree;
     332       
     333        fibril_rwlock_write_lock(&tree->rwlock);
     334
     335        dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
     336       
     337        if (pdev == NULL) {
     338                fibril_rwlock_write_unlock(&tree->rwlock);
     339                async_answer_0(callid, ENOENT);
     340                return;
     341        }
     342       
     343        if (ftype != fun_inner && ftype != fun_exposed) {
     344                /* Unknown function type */
     345                log_msg(LVL_ERROR,
     346                    "Unknown function type %d provided by driver.",
     347                    (int) ftype);
     348
     349                fibril_rwlock_write_unlock(&tree->rwlock);
     350                async_answer_0(callid, EINVAL);
     351                return;
     352        }
     353       
     354        char *fun_name = NULL;
     355        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     356        if (rc != EOK) {
     357                fibril_rwlock_write_unlock(&tree->rwlock);
     358                async_answer_0(callid, rc);
     359                return;
     360        }
     361       
     362        /* Check that function with same name is not there already. */
     363        if (find_fun_node_in_device(pdev, fun_name) != NULL) {
     364                fibril_rwlock_write_unlock(&tree->rwlock);
     365                async_answer_0(callid, EEXISTS);
     366                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     367                    fun_name);
     368                free(fun_name);
     369                return;
     370        }
     371       
     372        fun_node_t *fun = create_fun_node();
     373        fun->ftype = ftype;
     374       
     375        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     376                fibril_rwlock_write_unlock(&tree->rwlock);
     377                delete_fun_node(fun);
     378                async_answer_0(callid, ENOMEM);
     379                return;
     380        }
     381       
     382        fibril_rwlock_write_unlock(&tree->rwlock);
     383       
     384        devman_receive_match_ids(match_count, &fun->match_ids);
     385       
     386        rc = online_function(fun);
     387        if (rc != EOK) {
     388                /* XXX clean up */
     389                async_answer_0(callid, rc);
     390                return;
    339391        }
    340392       
     
    378430}
    379431
     432/** Online function by driver request.
     433 *
     434 */
     435static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     436    driver_t *drv)
     437{
     438        fun_node_t *fun;
     439        int rc;
     440
     441        printf("devman_drv_fun_online()\n");
     442        fibril_rwlock_write_lock(&device_tree.rwlock);
     443        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     444        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     445       
     446        if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
     447                async_answer_0(iid, ENOENT);
     448                return;
     449        }
     450       
     451        rc = online_function(fun);
     452        if (rc != EOK) {
     453                printf("devman_drv_fun_online() online_fun->ERROR\n");
     454                async_answer_0(iid, (sysarg_t) rc);
     455                return;
     456        }
     457        printf("devman_drv_fun_online() online_fun->OK\n");
     458       
     459        async_answer_0(iid, (sysarg_t) EOK);
     460}
     461
     462
     463/** Offline function by driver request.
     464 *
     465 */
     466static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     467    driver_t *drv)
     468{
     469        fun_node_t *fun;
     470        int rc;
     471
     472        fibril_rwlock_write_lock(&device_tree.rwlock);
     473        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     474        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     475       
     476        if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
     477                async_answer_0(iid, ENOENT);
     478                return;
     479        }
     480       
     481        rc = offline_function(fun);
     482        if (rc != EOK) {
     483                async_answer_0(iid, (sysarg_t) rc);
     484                return;
     485        }
     486       
     487        async_answer_0(iid, (sysarg_t) EOK);
     488}
     489
    380490/** Remove function. */
    381491static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
     
    399509                /* Handle possible descendants */
    400510                /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
     511                if (fun->child != NULL) {
     512                        log_msg(LVL_WARN, "devman_remove_function(): not handling "
     513                            "descendants\n");
     514                }
    403515        } else {
    404                 /* Unregister from location service */
    405                 rc = loc_service_unregister(fun->service_id);
    406                 if (rc != EOK) {
    407                         log_msg(LVL_ERROR, "Failed unregistering tree service.");
    408                         fibril_rwlock_write_unlock(&tree->rwlock);
    409                         async_answer_0(callid, EIO);
    410                         return;
     516                if (fun->service_id != 0) {
     517                        /* Unregister from location service */
     518                        rc = loc_service_unregister(fun->service_id);
     519                        if (rc != EOK) {
     520                                log_msg(LVL_ERROR, "Failed unregistering tree "
     521                                    "service.");
     522                                fibril_rwlock_write_unlock(&tree->rwlock);
     523                                async_answer_0(callid, EIO);
     524                                return;
     525                        }
    411526                }
    412527        }
     
    485600                        devman_add_function_to_cat(callid, &call);
    486601                        break;
     602                case DEVMAN_DRV_FUN_ONLINE:
     603                        devman_drv_fun_online(callid, &call, driver);
     604                        break;
     605                case DEVMAN_DRV_FUN_OFFLINE:
     606                        devman_drv_fun_offline(callid, &call, driver);
     607                        break;
    487608                case DEVMAN_REMOVE_FUNCTION:
    488609                        devman_remove_function(callid, &call);
    489610                        break;
    490611                default:
    491                         async_answer_0(callid, EINVAL); 
     612                        async_answer_0(callid, EINVAL);
    492613                        break;
    493614                }
     
    666787}
    667788
     789/** Online function.
     790 *
     791 * Send a request to online a function to the responsible driver.
     792 * The driver may offline other functions if necessary (i.e. if the state
     793 * of this function is linked to state of another function somehow).
     794 */
     795static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     796{
     797        fun_node_t *fun;
     798        int rc;
     799
     800        fibril_rwlock_write_lock(&device_tree.rwlock);
     801        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     802        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     803       
     804        if (fun == NULL) {
     805                async_answer_0(iid, ENOENT);
     806                return;
     807        }
     808       
     809        rc = driver_fun_online(fun);
     810       
     811        async_answer_0(iid, (sysarg_t) rc);
     812}
     813
     814/** Offline function.
     815 *
     816 * Send a request to offline a function to the responsible driver. As
     817 * a result the subtree rooted at that function should be cleanly
     818 * detatched. The driver may offline other functions if necessary
     819 * (i.e. if the state of this function is linked to state of another
     820 * function somehow).
     821 */
     822static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     823{
     824        fun_node_t *fun;
     825        int rc;
     826
     827        fibril_rwlock_write_lock(&device_tree.rwlock);
     828        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     829        fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
     830       
     831        if (fun == NULL) {
     832                async_answer_0(iid, ENOENT);
     833                return;
     834        }
     835       
     836        rc = driver_fun_offline(fun);
     837       
     838        async_answer_0(iid, (sysarg_t) rc);
     839}
     840
    668841/** Find handle for the function instance identified by its service ID. */
    669842static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
     
    709882                case DEVMAN_FUN_GET_PATH:
    710883                        devman_fun_get_path(callid, &call);
     884                        break;
     885                case DEVMAN_FUN_ONLINE:
     886                        devman_fun_online(callid, &call);
     887                        break;
     888                case DEVMAN_FUN_OFFLINE:
     889                        devman_fun_offline(callid, &call);
    711890                        break;
    712891                case DEVMAN_FUN_SID_TO_HANDLE:
Note: See TracChangeset for help on using the changeset viewer.