diff options
author | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2010-07-13 09:42:45 +0000 |
---|---|---|
committer | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2010-07-13 09:42:45 +0000 |
commit | d6035ac6ad1c10d867c57cd53e074fa521a537b0 (patch) | |
tree | 9af22ba8a433532636b3d6c7936f26fbed9ddab1 | |
parent | 330259c92d09fba56efca9d5be4cd2b237645725 (diff) |
put xbus->worker in xbus; wake_up_interruptible_all()
* The worker member of 'struct xbus' is now an embedded struct xbus_workqueue.
* Replace wake_up() to wake_up_interruptible_all().
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8882 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r-- | drivers/dahdi/xpp/card_global.c | 25 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.c | 162 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-core.h | 5 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xbus-sysfs.c | 7 | ||||
-rw-r--r-- | drivers/dahdi/xpp/xpp_dahdi.c | 7 |
5 files changed, 114 insertions, 92 deletions
diff --git a/drivers/dahdi/xpp/card_global.c b/drivers/dahdi/xpp/card_global.c index f8f79b2..2428cbe 100644 --- a/drivers/dahdi/xpp/card_global.c +++ b/drivers/dahdi/xpp/card_global.c @@ -576,13 +576,17 @@ HANDLER_DEF(GLOBAL, NULL_REPLY) HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ { - struct xbus_workqueue *worker = xbus->worker; + struct xbus_workqueue *worker; byte rev; struct unit_descriptor *units; int count_units; int i; int ret = 0; + if (!xbus) { + NOTICE("%s: xbus is gone!!!\n", __func__); + goto out; + } rev = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, rev); units = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, unit_descriptor); count_units = XPACKET_LEN(pack) - ((byte *)units - (byte *)pack); @@ -611,10 +615,11 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ } XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev); xbus->revision = rev; - if(!worker) { - XBUS_ERR(xbus, "missing worker\n"); + worker = &xbus->worker; + if (!worker->wq) { + XBUS_ERR(xbus, "missing worker thread\n"); ret = -ENODEV; - goto err; + goto out; } for(i = 0; i < count_units; i++) { struct unit_descriptor *this_unit = &units[i]; @@ -624,7 +629,7 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ if((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) { XBUS_ERR(xbus, "Card description allocation failed.\n"); ret = -ENOMEM; - goto err; + goto out; } card_desc->magic = CARD_DESC_MAGIC; INIT_LIST_HEAD(&card_desc->card_list); @@ -650,12 +655,14 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ list_add_tail(&card_desc->card_list, &worker->card_list); spin_unlock_irqrestore(&worker->worker_lock, flags); } - if(!xbus_process_worker(xbus)) - return -ENODEV; - return 0; + if (!xbus_process_worker(xbus)) { + ret = -ENODEV; + goto out; + } + goto out; proto_err: dump_packet("AB_DESCRIPTION", pack, DBG_ANY); -err: +out: return ret; } 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, diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h index 71be6bf..259f87a 100644 --- a/drivers/dahdi/xpp/xbus-core.h +++ b/drivers/dahdi/xpp/xbus-core.h @@ -127,7 +127,6 @@ void transportops_put(xbus_t *xbus); * Encapsulate all poll related data of a single xbus. */ struct xbus_workqueue { - xbus_t *xbus; struct workqueue_struct *wq; struct work_struct xpds_init_work; bool xpds_init_done; @@ -141,6 +140,7 @@ struct xbus_workqueue { #endif #endif spinlock_t worker_lock; + struct semaphore running_initialization; }; /* @@ -224,8 +224,7 @@ struct xbus { int sample_pos; #endif - struct xbus_workqueue *worker; - struct semaphore in_worker; + struct xbus_workqueue worker; /* * Sync adjustment diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c index 9634cd2..d107f39 100644 --- a/drivers/dahdi/xpp/xbus-sysfs.c +++ b/drivers/dahdi/xpp/xbus-sysfs.c @@ -781,7 +781,7 @@ int xpd_device_register(xbus_t *xbus, xpd_t *xpd) XPD_ERR(xpd, "%s: device_register failed: %d\n", __FUNCTION__, ret); return ret; } - get_xpd(__FUNCTION__, xpd); + xpd = get_xpd(__func__, xpd); /* Released in xbus_release_xpds() */ BUG_ON(!xpd); return 0; } @@ -811,12 +811,12 @@ void xbus_sysfs_remove(xbus_t *xbus) BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); astribank = &xbus->astribank; - BUG_ON(!astribank); sysfs_remove_link(&astribank->kobj, "transport"); if(!dev_get_drvdata(astribank)) return; BUG_ON(dev_get_drvdata(astribank) != xbus); - device_unregister(&xbus->astribank); + device_unregister(astribank); + dev_set_drvdata(astribank, NULL); } int xbus_sysfs_create(xbus_t *xbus) @@ -826,7 +826,6 @@ int xbus_sysfs_create(xbus_t *xbus) BUG_ON(!xbus); astribank = &xbus->astribank; - BUG_ON(!astribank); XBUS_DBG(DEVICES, xbus, "\n"); astribank->bus = &toplevel_bus_type; astribank->parent = xbus->transport.transport_device; diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c index 26fa223..443885c 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.c +++ b/drivers/dahdi/xpp/xpp_dahdi.c @@ -249,6 +249,9 @@ void xpd_free(xpd_t *xpd) } KZFREE(xpd); DBG(DEVICES, "refcount_xbus=%d\n", refcount_xbus(xbus)); + /* + * This must be last, so the xbus cannot be released before the xpd + */ put_xbus(__FUNCTION__, xbus); /* was taken in xpd_alloc() */ } @@ -555,6 +558,10 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus, xbus_xpd_bind(xbus, xpd, unit, subunit); if(xpd_proc_create(xbus, xpd) < 0) goto err; + /* + * This makes sure the xbus cannot be removed before this xpd + * is removed in xpd_free() + */ xbus = get_xbus(__FUNCTION__, xbus); /* returned in xpd_free() */ xproto_get(type); /* will be returned in xpd_free() */ return xpd; |