summaryrefslogtreecommitdiff
path: root/drivers/dahdi
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2010-07-13 09:42:45 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2010-07-13 09:42:45 +0000
commitd6035ac6ad1c10d867c57cd53e074fa521a537b0 (patch)
tree9af22ba8a433532636b3d6c7936f26fbed9ddab1 /drivers/dahdi
parent330259c92d09fba56efca9d5be4cd2b237645725 (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
Diffstat (limited to 'drivers/dahdi')
-rw-r--r--drivers/dahdi/xpp/card_global.c25
-rw-r--r--drivers/dahdi/xpp/xbus-core.c162
-rw-r--r--drivers/dahdi/xpp/xbus-core.h5
-rw-r--r--drivers/dahdi/xpp/xbus-sysfs.c7
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.c7
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;