diff options
Diffstat (limited to 'drivers/dahdi/xpp/xbus-core.c')
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.c | 162 |
1 files changed, 86 insertions, 76 deletions
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c index 3906f41..79f417a 100644 --- a/drivers/dahdi/xpp/xbus-core.c +++ b/drivers/dahdi/xpp/xbus-core.c @@ -760,7 +760,7 @@ static int new_card(xbus_t *xbus, ); xops = &proto_table->xops; BUG_ON(!xops); - xbus->worker->num_units += subunits - 1; + xbus->worker.num_units += subunits - 1; for(i = 0; i < subunits; i++) { int subunit_ports = proto_table->ports_per_subunit; @@ -803,7 +803,7 @@ static int new_card(xbus_t *xbus, unit, i, ret); goto out; } - xbus->worker->num_units_initialized++; + xbus->worker.num_units_initialized++; } out: xproto_put(proto_table); /* ref count is inside the xpds now */ @@ -819,7 +819,8 @@ static void xbus_release_xpds(xbus_t *xbus) xpd_t *xpd = xpd_of(xbus, i); if(xpd) - put_xpd(__FUNCTION__, xpd); /* taken in xbus_xpd_bind() */ + /* taken in xpd_device_register() */ + put_xpd(__func__, xpd); } } @@ -913,7 +914,7 @@ void xbus_populate(void *data) unsigned long flags; int ret = 0; - xbus = worker->xbus; + xbus = container_of(worker, xbus_t, worker); XBUS_DBG(DEVICES, xbus, "Entering %s\n", __FUNCTION__); spin_lock_irqsave(&worker->worker_lock, flags); list_for_each_safe(card, next_card, &worker->card_list) { @@ -922,7 +923,7 @@ void xbus_populate(void *data) list_del(card); BUG_ON(card_desc->magic != CARD_DESC_MAGIC); /* Release/Reacquire locks around blocking calls */ - spin_unlock_irqrestore(&xbus->worker->worker_lock, flags); + spin_unlock_irqrestore(&xbus->worker.worker_lock, flags); ret = new_card(xbus, card_desc->xpd_addr.unit, card_desc->type, @@ -931,7 +932,7 @@ void xbus_populate(void *data) card_desc->ports_per_chip, card_desc->ports, card_desc->port_dir); - spin_lock_irqsave(&xbus->worker->worker_lock, flags); + spin_lock_irqsave(&xbus->worker.worker_lock, flags); KZFREE(card_desc); if(ret) break; @@ -957,9 +958,9 @@ void xbus_populate(void *data) elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */ out: XBUS_DBG(DEVICES, xbus, "Leaving\n"); - wake_up(&worker->wait_for_xpd_initialization); + wake_up_interruptible_all(&worker->wait_for_xpd_initialization); XBUS_DBG(DEVICES, xbus, "populate release\n"); - up(&xbus->in_worker); + up(&worker->running_initialization); return; failed: xbus_setstate(xbus, XBUS_STATE_FAIL); @@ -968,13 +969,14 @@ failed: int xbus_process_worker(xbus_t *xbus) { - struct xbus_workqueue *worker = xbus->worker; + struct xbus_workqueue *worker; if(!xbus) { ERR("%s: xbus gone -- skip initialization\n", __FUNCTION__); return 0; } - if(down_trylock(&xbus->in_worker)) { + worker = &xbus->worker; + if (down_trylock(&worker->running_initialization)) { ERR("%s: xbus is disconnected -- skip initialization\n", __FUNCTION__); return 0; } @@ -989,22 +991,24 @@ int xbus_process_worker(xbus_t *xbus) /* Now send it */ if(!queue_work(worker->wq, &worker->xpds_init_work)) { XBUS_ERR(xbus, "Failed to queue xpd initialization work\n"); - up(&xbus->in_worker); + up(&worker->running_initialization); return 0; } return 1; } -static void worker_reset(struct xbus_workqueue *worker) +static void worker_reset(xbus_t *xbus) { - + struct xbus_workqueue *worker; struct list_head *card; struct list_head *next_card; unsigned long flags; - xbus_t *xbus = worker->xbus; - char *name = (xbus) ? xbus->busname : "detached"; + char *name; - BUG_ON(!worker); + BUG_ON(!xbus); + worker = &xbus->worker; + xbus = container_of(worker, xbus_t, worker); + name = (xbus) ? xbus->busname : "detached"; DBG(DEVICES, "%s\n", name); if(!worker->xpds_init_done) { NOTICE("%s: worker(%s)->xpds_init_done=%d\n", @@ -1021,43 +1025,54 @@ static void worker_reset(struct xbus_workqueue *worker) worker->xpds_init_done = 0; worker->num_units = 0; worker->num_units_initialized = 0; + wake_up_interruptible_all(&worker->wait_for_xpd_initialization); spin_unlock_irqrestore(&worker->worker_lock, flags); - wake_up(&worker->wait_for_xpd_initialization); } -static void worker_destroy(struct xbus_workqueue *worker) +static void worker_destroy(xbus_t *xbus) { - xbus_t *xbus; + struct xbus_workqueue *worker; - if(!worker) - return; - worker_reset(worker); - xbus = worker->xbus; - if(xbus) { - XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish...\n"); - down(&xbus->in_worker); - XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish -- done\n"); - if (worker->wq) { - XBUS_DBG(DEVICES, xbus, "destroying workqueue...\n"); - flush_workqueue(worker->wq); - destroy_workqueue(worker->wq); - worker->wq = NULL; - XBUS_DBG(DEVICES, xbus, "destroying workqueue -- done\n"); - } + BUG_ON(!xbus); + worker = &xbus->worker; + worker_reset(xbus); + XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish...\n"); + down(&worker->running_initialization); + XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish -- done\n"); + if (worker->wq) { + XBUS_DBG(DEVICES, xbus, "destroying workqueue...\n"); + flush_workqueue(worker->wq); + destroy_workqueue(worker->wq); + worker->wq = NULL; + XBUS_DBG(DEVICES, xbus, "destroying workqueue -- done\n"); + } #ifdef CONFIG_PROC_FS #ifdef OLD_PROC - if(xbus->proc_xbus_dir && worker->proc_xbus_waitfor_xpds) { - XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_WAITFOR_XPDS); - remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir); - worker->proc_xbus_waitfor_xpds = NULL; - } + if (xbus->proc_xbus_dir && worker->proc_xbus_waitfor_xpds) { + XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", + PROC_XBUS_WAITFOR_XPDS); + remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir); + worker->proc_xbus_waitfor_xpds = NULL; + } #endif #endif - XBUS_DBG(DEVICES, xbus, "detach worker\n"); - xbus->worker = NULL; - KZFREE(worker); - put_xbus(__FUNCTION__, xbus); /* got from worker_new() */ - } + XBUS_DBG(DEVICES, xbus, "detach worker\n"); + put_xbus(__func__, xbus); /* got from worker_run() */ +} + +static void worker_init(xbus_t *xbus) +{ + struct xbus_workqueue *worker; + + BUG_ON(!xbus); + XBUS_DBG(DEVICES, xbus, "\n"); + worker = &xbus->worker; + /* poll related variables */ + spin_lock_init(&worker->worker_lock); + INIT_LIST_HEAD(&worker->card_list); + init_waitqueue_head(&worker->wait_for_xpd_initialization); + worker->wq = NULL; + init_MUTEX(&xbus->worker.running_initialization); } /* @@ -1065,25 +1080,17 @@ static void worker_destroy(struct xbus_workqueue *worker) * May call blocking operations, but only briefly (as we are called * from xbus_new() which is called from khubd. */ -static struct xbus_workqueue *worker_new(int xbusno) +static int worker_run(xbus_t *xbus) { struct xbus_workqueue *worker; - xbus_t *xbus; - if((xbus = xbus_num(xbusno)) == NULL) - return NULL; - get_xbus(__FUNCTION__, xbus); /* return in worker_destroy() */ + xbus = get_xbus(__func__, xbus); /* return in worker_destroy() */ + BUG_ON(!xbus); BUG_ON(xbus->busname[0] == '\0'); /* No name? */ - BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */ + worker = &xbus->worker; + BUG_ON(worker->wq); /* Hmmm... nested workers? */ XBUS_DBG(DEVICES, xbus, "\n"); - worker = KZALLOC(sizeof(*worker), GFP_KERNEL); - if(!worker) - goto err; /* poll related variables */ - spin_lock_init(&worker->worker_lock); - INIT_LIST_HEAD(&worker->card_list); - init_waitqueue_head(&worker->wait_for_xpd_initialization); - worker->xbus = xbus; #ifdef CONFIG_PROC_FS #ifdef OLD_PROC if(xbus->proc_xbus_dir) { @@ -1105,10 +1112,10 @@ static struct xbus_workqueue *worker_new(int xbusno) XBUS_ERR(xbus, "Failed to create worker workqueue.\n"); goto err; } - return worker; + return 1; err: - worker_destroy(worker); - return NULL; + worker_destroy(xbus); + return 0; } bool xbus_setflags(xbus_t *xbus, int flagbit, bool on) @@ -1223,14 +1230,11 @@ int xbus_activate(xbus_t *xbus) int xbus_connect(xbus_t *xbus) { struct xbus_ops *ops; - struct xbus_workqueue *worker; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); ops = transportops_get(xbus); BUG_ON(!ops); - worker = xbus->worker; - BUG_ON(!worker); /* Sanity checks */ BUG_ON(!ops->xframe_send_pcm); BUG_ON(!ops->xframe_send_cmd); @@ -1253,7 +1257,7 @@ void xbus_deactivate(xbus_t *xbus) xbus_command_queue_clean(xbus); xbus_command_queue_waitempty(xbus); xbus_setstate(xbus, XBUS_STATE_DEACTIVATED); - worker_reset(xbus->worker); + worker_reset(xbus); xbus_release_xpds(xbus); elect_syncer("deactivate"); } @@ -1274,7 +1278,7 @@ void xbus_disconnect(xbus_t *xbus) del_timer_sync(&xbus->command_timer); transportops_put(xbus); transport_destroy(xbus); - worker_destroy(xbus->worker); + worker_destroy(xbus); XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n", refcount_xbus(xbus)); xbus_sysfs_remove(xbus); /* Device-Model */ @@ -1377,11 +1381,11 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran spin_lock_init(&xbus->lock); init_waitqueue_head(&xbus->command_queue_empty); init_timer(&xbus->command_timer); - init_MUTEX(&xbus->in_worker); atomic_set(&xbus->pcm_rx_counter, 0); xbus->min_tx_sync = INT_MAX; xbus->min_rx_sync = INT_MAX; + worker_init(xbus); atomic_set(&xbus->num_xpds, 0); xbus->sync_mode = SYNC_MODE_NONE; err = xbus_sysfs_create(xbus); @@ -1442,8 +1446,7 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran * Create worker after /proc/XBUS-?? so the directory exists * before /proc/XBUS-??/waitfor_xpds tries to get created. */ - xbus->worker = worker_new(xbus->num); - if(!xbus->worker) { + if (!worker_run(xbus)) { ERR("Failed to allocate worker\n"); goto nobus; } @@ -1467,14 +1470,11 @@ void xbus_reset_counters(xbus_t *xbus) static bool xpds_done(xbus_t *xbus) { - struct xbus_workqueue *worker; - if (XBUS_IS(xbus, FAIL)) return 1; /* Nothing to wait for */ if (!XBUS_IS(xbus, RECVD_DESC)) return 1; /* We are not in the initialization phase */ - worker = xbus->worker; - if (worker->xpds_init_done) + if (xbus->worker.xpds_init_done) return 1; /* All good */ /* Keep waiting */ return 0; @@ -1494,12 +1494,22 @@ int waitfor_xpds(xbus_t *xbus, char *buf) xbus = get_xbus(__func__, xbus); /* until end of waitfor_xpds_show() */ if (!xbus) return -ENODEV; - worker = xbus->worker; + worker = &xbus->worker; BUG_ON(!worker); + if (!worker->wq) { + XBUS_ERR(xbus, "Missing worker thread. Skipping.\n"); + len = -ENODEV; + goto out; + } + if (worker->num_units == 0) { + XBUS_ERR(xbus, "No cards. Skipping.\n"); + goto out; + } XBUS_DBG(DEVICES, xbus, - "Waiting for card initialization of %d XPD's max %d seconds\n", + "Waiting for card init of %d XPD's max %d seconds (%p)\n", worker->num_units, - INITIALIZATION_TIMEOUT/HZ); + INITIALIZATION_TIMEOUT/HZ, + &worker->wait_for_xpd_initialization); ret = wait_event_interruptible_timeout( worker->wait_for_xpd_initialization, xpds_done(xbus), @@ -1564,7 +1574,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e goto out; xbus = get_xbus(__FUNCTION__, xbus); /* until end of xbus_read_proc */ spin_lock_irqsave(&xbus->lock, flags); - worker = xbus->worker; + worker = &xbus->worker; len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", xbus->busname, |