summaryrefslogtreecommitdiff
path: root/kernel/xpp/xbus-core.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-05-13 21:08:09 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-05-13 21:08:09 +0000
commitd7e54a785544ac40abc4a88383df3a913ca466e8 (patch)
treeabf630c8372e7c81407172ad31190fa8a617a8ed /kernel/xpp/xbus-core.c
parent823cf303caf13cc6e4fd2c2173804f0990b29532 (diff)
xpp r5723: Includes, among others:
* New firmware protocol version: 3.0 . * New numbers for the device types: (e.g. in card_init* scripts) - FXS: 1 (was: 3) - FXO: 2 (was: 4) - BRI: 3 (was: 6 for TE, 7 for NT) - PRI: 4 (was: 9) * Init scripts of FXS and FXO modules are now written in Perl as well (be sure to have File::Basename, e.g: perl-modules in Debian). * calibrate_slics merged into init_card_1_30 . * Module parameter print_dbg replaced with debug . Same meaning. * init_fxo_modes removed: content moved into init_card_2_30, verified at build time. * Code tested with sparse. Most warnings were fixed. * Set ZT_SIG_DACS for the bchans in the PRI and BRI modules to not get ignored by ztscan. * Handle null config_desc we get from some crazy USB controllers. * genzaptelconf: Fix reporting of empty slots in list mode. * xpp_blink can now blink a single analog port. * "slics" has been renamed "chipregs". * Fixed a small typo in fpga_load(8). * Fixed bashism in xpp_fxloader. Merged revisions 4264 via svnmerge from http://svn.digium.com/svn/zaptel/branches/1.2 git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4266 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/xpp/xbus-core.c')
-rw-r--r--kernel/xpp/xbus-core.c548
1 files changed, 236 insertions, 312 deletions
diff --git a/kernel/xpp/xbus-core.c b/kernel/xpp/xbus-core.c
index 385f542..26c31f5 100644
--- a/kernel/xpp/xbus-core.c
+++ b/kernel/xpp/xbus-core.c
@@ -38,6 +38,7 @@
#include "xpd.h"
#include "xpp_zap.h"
#include "xbus-core.h"
+#include "card_global.h"
#ifdef XPP_DEBUGFS
#include "xpp_log.h"
#endif
@@ -46,7 +47,7 @@
static const char rcsid[] = "$Id$";
/* Defines */
-#define INITIALIZATION_TIMEOUT (60*HZ) /* in jiffies */
+#define INITIALIZATION_TIMEOUT (90*HZ) /* in jiffies */
#define PROC_XBUSES "xbuses"
#define PROC_XBUS_SUMMARY "summary"
#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
@@ -57,37 +58,15 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
#endif
/* Command line parameters */
-extern int print_dbg;
-DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply");
-DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
+extern int debug;
+static DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply");
+static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data);
static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv);
static void transport_destroy(xbus_t *xbus);
-/*
- * Encapsulate all poll related data of a single xbus.
- */
-struct xbus_poller {
- /*
- * Bus scanning
- */
- uint xbus_num;
- struct workqueue_struct *wq;
- bool is_polling;
- atomic_t count_poll_answers;
- struct list_head poll_results;
- wait_queue_head_t wait_for_polls;
-
- struct work_struct xpds_init_work;
-
- atomic_t count_xpds_to_initialize;
- atomic_t count_xpds_initialized;
- wait_queue_head_t wait_for_xpd_initialization;
- struct proc_dir_entry *proc_xbus_waitfor_xpds;
-};
-
/* Data structures */
static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
static int bus_count = 0;
@@ -110,7 +89,7 @@ static void init_xbus(uint num, xbus_t *xbus)
init_waitqueue_head(&desc->can_release_xbus);
}
-int refcount_xbus(uint num)
+static int refcount_xbus(uint num)
{
BUG_ON(num >= ARRAY_SIZE(xbuses_array));
return atomic_read(&xbuses_array[num].xbus_refcount);
@@ -149,7 +128,7 @@ void put_xbus(xbus_t *xbus)
}
}
-bool __must_check wait_for_xbus_release(uint xbus_num)
+static bool __must_check wait_for_xbus_release(uint xbus_num)
{
xbus_t *xbus;
int ret;
@@ -383,13 +362,13 @@ static spinlock_t serialize_dump_xframe = SPIN_LOCK_UNLOCKED;
static void do_hexdump(const char msg[], byte *data, uint16_t len)
{
int i;
- int print_dbg = DBG_ANY; /* mask global print_dbg */
+ int debug = DBG_ANY; /* mask global debug */
for(i = 0; i < len; i++)
DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]);
}
-void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int print_dbg)
+void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug)
{
const uint16_t frm_len = XFRAME_LEN(xframe);
xpacket_t *pack;
@@ -441,12 +420,12 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
break;
}
do_print = 0;
- if(print_dbg == DBG_ANY)
+ if(debug == DBG_ANY)
do_print = 1;
else if(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ) &&
XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_WRITE))
do_print = 1;
- else if(print_dbg & DBG_PCM) {
+ else if(debug & DBG_PCM) {
static int rate_limit;
if((rate_limit++ % 1003) == 0)
@@ -466,7 +445,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
XPACKET_OP(pack),
XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack),
pos);
- dump_packet(" ", pack, print_dbg);
+ dump_packet(" ", pack, debug);
}
num++;
pos = nextpos;
@@ -476,7 +455,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
spin_unlock_irqrestore(&serialize_dump_xframe, flags);
}
-bool xbus_ready(const xbus_t *xbus, const char msg[])
+static bool xbus_ready(const xbus_t *xbus, const char msg[])
{
if(!xbus) {
ERR("null xbus: %s\n", msg);
@@ -536,6 +515,8 @@ static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
}
ops = transportops_get(xbus);
BUG_ON(!ops);
+ if(debug & DBG_COMMANDS)
+ dump_xframe("TX-CMD", xbus, xframe, DBG_ANY);
ret = ops->xframe_send_cmd(xbus, xframe);
transportops_put(xbus);
if(ret == 0) {
@@ -752,159 +733,169 @@ out:
}
/*
- * This must be called from synchronous (non-interrupt) context
- * it returns only when all XPD's on the bus are detected and
- * initialized.
+ * Called with xbus->worker locked.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-static void xbus_poll(struct work_struct *work)
-{
- struct xbus_poller *poller = container_of(work, struct xbus_poller, xpds_init_work);
-#else
-static void xbus_poll(void *data)
+static int new_card(xbus_t *xbus,
+ int unit,
+ byte type,
+ byte subtype,
+ byte numchips,
+ byte ports_per_chip,
+ byte ports,
+ byte port_dir)
{
- struct xbus_poller *poller = data;
-#endif
- int id;
+ const xproto_table_t *proto_table;
+ const xops_t *xops;
+ int i;
+ int subunits;
int ret = 0;
- unsigned long flags;
- struct list_head *card;
- struct list_head *next_card;
- struct list_head removal_list;
- struct list_head additions_list;
- int count_removed;
- int count_added;
- xbus_t *xbus;
- BUG_ON(!poller);
- xbus = get_xbus(poller->xbus_num);
- if(!xbus) {
- XBUS_ERR(xbus, "Aborting poll. XBUS #%d disappeared.\n",
- poller->xbus_num);
- return;
- }
- msleep(2); /* roundtrip for older polls */
- spin_lock_irqsave(&xbus->lock, flags);
- XBUS_DBG(DEVICES, xbus, "\n");
- poller->is_polling = 1;
- if(!XBUS_GET(xbus)) {
- XBUS_ERR(xbus, "Aborting poll. Is shutting down.\n");
- goto out; /* FIXME: should not XBUS_PUT() in that case */
- }
- /*
- * Send out the polls
- */
- for(id = 0; id < MAX_XPDS; id++) {
- if(!TRANSPORT_RUNNING(xbus))
- break;
- XBUS_DBG(DEVICES, xbus, "Polling slot %d\n", id);
- spin_unlock_irqrestore(&xbus->lock, flags);
- ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
- spin_lock_irqsave(&xbus->lock, flags);
+ proto_table = xproto_get(type);
+ if(!proto_table) {
+ XBUS_NOTICE(xbus,
+ "CARD %d: missing protocol table for type %d. Ignored.\n",
+ unit, type);
+ return -EINVAL;
+ }
+ subunits = (ports + proto_table->ports_per_subunit - 1) /
+ proto_table->ports_per_subunit;
+ XBUS_DBG(DEVICES, xbus, "CARD %d type=%d.%d ports=%d (%dx%d), %d subunits, port-dir=0x%02X\n",
+ unit,
+ type,
+ subtype,
+ ports,
+ numchips,
+ ports_per_chip,
+ subunits,
+ port_dir
+ );
+ xops = &proto_table->xops;
+ BUG_ON(!xops);
+ xbus->worker->num_units += subunits - 1;
+ for(i = 0; i < subunits; i++) {
+ if(!TRANSPORT_RUNNING(xbus)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ XBUS_DBG(DEVICES, xbus, "Creating XPD=%d%d type=%d.%d\n",
+ unit,
+ i,
+ type,
+ subtype);
+ if(!XBUS_GET(xbus)) {
+ XBUS_ERR(xbus, "Aborting creation. Is shutting down.\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = create_xpd(xbus, proto_table, unit, i, type, subtype, subunits, port_dir);
+ XBUS_PUT(xbus);
if(ret < 0) {
- XBUS_ERR(xbus, "Failed sending DESC_REQ to XPD #%d\n", id);
+ XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n",
+ unit, i, ret);
goto out;
}
+ xbus->worker->num_units_initialized++;
}
- spin_unlock_irqrestore(&xbus->lock, flags);
- /*
- * Wait for replies
- */
- XBUS_DBG(DEVICES, xbus, "Polled %d XPD's. Waiting for replies max %d jiffies\n", MAX_XPDS, poll_timeout);
- ret = wait_event_interruptible_timeout(poller->wait_for_polls, atomic_read(&poller->count_poll_answers) >= MAX_XPDS, poll_timeout);
- if(ret == 0) {
- XBUS_ERR(xbus, "Poll timeout. Continuing anyway.\n");
- /*
- * Continue processing. Maybe some units did reply.
- */
- } else if(ret < 0) {
- XBUS_ERR(xbus, "Poll interrupted %d\n", ret);
- goto out;
- } else
- XBUS_DBG(DEVICES, xbus, "Poll finished in %d jiffies.\n", poll_timeout - ret);
- /*
- * Build removals/additions lists
- */
- spin_lock_irqsave(&xbus->lock, flags);
- INIT_LIST_HEAD(&removal_list);
- INIT_LIST_HEAD(&additions_list);
- count_removed = 0;
- count_added = 0;
- list_for_each_safe(card, next_card, &poller->poll_results) {
- struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
- byte type = card_desc->type;
- xpd_t *xpd;
+out:
+ xproto_put(proto_table); /* ref count is inside the xpds now */
+ return ret;
+}
- BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
- /*
- * Return the refcount we got in xbus_poller_notify()
- * We are still protected by the refcount taken in
- * the beginning of xbus_poll().
- */
- put_xbus(xbus);
- xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit);
-
- if(xpd && type == XPD_TYPE_NOMODULE) { /* card removal */
- list_move_tail(card, &removal_list);
- count_removed++;
- } else if(!xpd && type != XPD_TYPE_NOMODULE) { /* card detection */
- if(card_desc->rev != XPP_PROTOCOL_VERSION) {
- XBUS_NOTICE(xbus, "XPD at %d%d: type=%d.%d has bad firmware revision %d.%d\n",
- card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
- card_desc->type, card_desc->subtype,
- card_desc->rev / 10, card_desc->rev % 10);
- list_del(card);
- kfree(card_desc);
+static int xbus_initialize(xbus_t *xbus)
+{
+ int unit;
+ int subunit;
+ xpd_t *xpd;
+
+ for(unit = 0; unit < MAX_UNIT; unit++) {
+ xpd = xpd_byaddr(xbus, unit, 0);
+ if(!xpd)
+ continue;
+ if(run_initialize_registers(xpd) < 0) {
+ XPD_ERR(xpd, "Register Initialization failed\n");
+ goto err;
+ }
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd = xpd_byaddr(xbus, unit, subunit);
+ if(!xpd)
continue;
+ if(CALL_XMETHOD(card_init, xpd->xbus, xpd) < 0) {
+ XPD_ERR(xpd, "Card Initialization failed\n");
+ goto err;
}
- XBUS_INFO(xbus, "Detected XPD at %d%d type=%d.%d Revision %d.%d\n",
- card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
- card_desc->type, card_desc->subtype,
- card_desc->rev / 10, card_desc->rev % 10);
- list_move_tail(card, &additions_list);
- count_added++;
- } else { /* same same */
- list_del(card);
- kfree(card_desc);
+ //CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0); /* Turn off all channels */
+ xpd->card_present = 1;
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); /* Turn on all channels */
+ XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name);
+ xpd_post_init(xpd);
}
}
- poller->is_polling = 0;
- /*
- * We set this *after* poll is finished, so wait_for_xpd_initialization can
- * tell we already know how many units we have.
- */
- atomic_set(&poller->count_xpds_to_initialize, count_added);
- spin_unlock_irqrestore(&xbus->lock, flags);
- XBUS_INFO(xbus, "Poll results: removals=%d additions=%d\n", count_removed, count_added);
- /*
- * Process removals first
- */
- list_for_each_safe(card, next_card, &removal_list) {
- struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
- xpd_t *xpd;
+ return 0;
+err:
+ for(unit = 0; unit < MAX_UNIT; unit++) {
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd = xpd_byaddr(xbus, unit, subunit);
+ if(!xpd)
+ xpd_free(xpd);
+ }
+ }
+ return -EINVAL;
+}
- list_del(card);
- xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit);
- if(xpd)
- xpd_disconnect(xpd);
- kfree(card);
+/*
+ * This must be called from synchronous (non-interrupt) context
+ * it returns only when all XPD's on the bus are detected and
+ * initialized.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+void xbus_populate(struct work_struct *work)
+{
+ struct xbus_workqueue *worker = container_of(work, struct xbus_workqueue, xpds_init_work);
+#else
+void xbus_populate(void *data)
+{
+ struct xbus_workqueue *worker = data;
+#endif
+ xbus_t *xbus;
+ struct list_head *card;
+ struct list_head *next_card;
+ unsigned long flags;
+ int ret = 0;
+
+ xbus = worker->xbus;
+ if(!XBUS_GET(xbus)) {
+ XBUS_NOTICE(xbus, "Shutting down, aboring initialization\n");
+ return;
}
- /*
- * Now process additions
- */
- list_for_each_safe(card, next_card, &additions_list) {
+ spin_lock_irqsave(&worker->worker_lock, flags);
+ list_for_each_safe(card, next_card, &worker->card_list) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
list_del(card);
- /* FIXME: card_detected() should have a return value for count_xpds_initialized */
- card_detected(card_desc);
- atomic_inc(&poller->count_xpds_initialized);
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ /* Release/Reacquire locks around blocking calls */
+ spin_unlock_irqrestore(&xbus->worker->worker_lock, flags);
+ ret = new_card(xbus,
+ card_desc->xpd_addr.unit,
+ card_desc->type,
+ card_desc->subtype,
+ card_desc->numchips,
+ card_desc->ports_per_chip,
+ card_desc->ports,
+ card_desc->port_dir);
+ spin_lock_irqsave(&xbus->worker->worker_lock, flags);
+ KZFREE(card_desc);
+ if(ret)
+ break;
}
- /* Device-Model */
- if((ret = xbus_sysfs_create(xbus)) < 0) {
- XBUS_ERR(xbus, "%s: xbus_sysfs_create() failed: %d\n", __FUNCTION__, ret);
- goto out;
+ spin_unlock_irqrestore(&worker->worker_lock, flags);
+ xbus_initialize(xbus);
+ worker->xpds_init_done = 1;
+ ret = xbus_sysfs_create(xbus);
+ if(ret) {
+ XBUS_ERR(xbus, "SYSFS creation failed: %d\n", ret);
}
+ wake_up(&worker->wait_for_xpd_initialization);
/*
* Now request Astribank to start self_ticking.
* This is the last initialization command. So
@@ -912,164 +903,107 @@ static void xbus_poll(void *data)
*/
xbus_request_sync(xbus, SYNC_MODE_PLL);
elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */
-out:
- poller->is_polling = 0; /* just for safety */
+ put_xbus(xbus); /* taken in AB_DESCRIPTION */
XBUS_PUT(xbus);
- wake_up(&poller->wait_for_xpd_initialization);
- put_xbus(xbus);
- return;
}
-void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc)
+static void worker_destroy(struct xbus_workqueue *worker)
{
- struct xbus_poller *poller;
+ xbus_t *xbus;
+ struct list_head *card;
+ struct list_head *next_card;
unsigned long flags;
- BUG_ON(!xbus);
- poller = xbus->poller;
- BUG_ON(!poller);
- if(!poller->is_polling) {
- XBUS_NOTICE(xbus, "%d%d replied not during poll. Ignore\n",
- card_desc->xpd_addr.unit,
- card_desc->xpd_addr.subunit);
- kfree(card_desc);
+ if(!worker)
return;
- }
- spin_lock_irqsave(&xbus->lock, flags);
- if(card_desc->type == XPD_TYPE_NOMODULE)
- XBUS_COUNTER(xbus, DEV_DESC_EMPTY)++;
- else
- XBUS_COUNTER(xbus, DEV_DESC_FULL)++;
- atomic_inc(&poller->count_poll_answers);
- list_add_tail(&card_desc->card_list, &poller->poll_results);
- spin_unlock_irqrestore(&xbus->lock, flags);
- /*
- * Reference counting for the xbus.
- * Would be returned in xbus_poll()
- */
- xbus = get_xbus(xbus->num);
- BUG_ON(!xbus);
- /*
- * wake_up only after exiting our critical section.
- * We suspect that otherwise a spinlock nesting may occur
- * and cause a panic (if spinlock debugging is compiled in).
- */
- wake_up(&poller->wait_for_polls);
- return;
-}
-
-static void poller_destroy(struct xbus_poller *poller)
-{
- xbus_t *xbus;
+ spin_lock_irqsave(&worker->worker_lock, flags);
+ xbus = worker->xbus;
+ list_for_each_safe(card, next_card, &worker->card_list) {
+ struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
- if(!poller)
- return;
- xbus = get_xbus(poller->xbus_num);
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ list_del(card);
+ kfree(card_desc);
+ }
+ spin_unlock_irqrestore(&worker->worker_lock, flags);
if(xbus) {
#ifdef CONFIG_PROC_FS
- if(xbus->proc_xbus_dir && poller->proc_xbus_waitfor_xpds) {
+ 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);
- poller->proc_xbus_waitfor_xpds = NULL;
+ worker->proc_xbus_waitfor_xpds = NULL;
}
#endif
- XBUS_DBG(DEVICES, xbus, "detach poller\n");
- xbus->poller = NULL;
+ XBUS_DBG(DEVICES, xbus, "detach worker\n");
+ xbus->worker = NULL;
}
- if (poller->wq) {
- DBG(DEVICES, "XBUS #%d: destroy workqueue\n", poller->xbus_num);
- flush_workqueue(poller->wq);
- destroy_workqueue(poller->wq);
- poller->wq = NULL;
+ if (worker->wq) {
+ DBG(DEVICES, "XBUS #%d: destroy workqueue\n", worker->xbus->num);
+ flush_workqueue(worker->wq);
+ destroy_workqueue(worker->wq);
+ worker->wq = NULL;
}
- put_xbus(xbus);
- KZFREE(poller);
+ put_xbus(xbus); /* Taken in worker_new() */
+ KZFREE(worker);
}
/*
- * Allocate a poller for the xbus including the nessessary workqueue.
+ * Allocate a worker for the xbus including the nessessary workqueue.
* May call blocking operations, but only briefly (as we are called
* from xbus_new() which is called from khubd.
*/
-static struct xbus_poller *poller_new(xbus_t *xbus)
+static struct xbus_workqueue *worker_new(int xbus_num)
{
- struct xbus_poller *poller;
+ struct xbus_workqueue *worker;
+ xbus_t *xbus;
+ xbus = get_xbus(xbus_num); /* release in worker_destroy */
BUG_ON(xbus->busname[0] == '\0'); /* No name? */
- BUG_ON(xbus->poller); /* Hmmm... overrun pollers? */
+ BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
XBUS_DBG(DEVICES, xbus, "\n");
- poller = KZALLOC(sizeof(*poller), GFP_KERNEL);
- if(!poller)
+ worker = KZALLOC(sizeof(*worker), GFP_KERNEL);
+ if(!worker)
goto err;
- poller->xbus_num = xbus->num;
- xbus->poller = poller;
+ worker->xbus = xbus;
/* poll related variables */
- atomic_set(&poller->count_poll_answers, 0);
- atomic_set(&poller->count_xpds_to_initialize, 0);
- atomic_set(&poller->count_xpds_initialized, 0);
- INIT_LIST_HEAD(&poller->poll_results);
- init_waitqueue_head(&poller->wait_for_polls);
- init_waitqueue_head(&poller->wait_for_xpd_initialization);
- poller->wq = create_singlethread_workqueue(xbus->busname);
- if(!poller->wq) {
- XBUS_ERR(xbus, "Failed to create poller workqueue.\n");
+ spin_lock_init(&worker->worker_lock);
+ INIT_LIST_HEAD(&worker->card_list);
+ init_waitqueue_head(&worker->wait_for_xpd_initialization);
+ worker->wq = create_singlethread_workqueue(xbus->busname);
+ if(!worker->wq) {
+ XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
goto err;
}
#ifdef CONFIG_PROC_FS
if(xbus->proc_xbus_dir) {
- poller->proc_xbus_waitfor_xpds = create_proc_read_entry(
+ worker->proc_xbus_waitfor_xpds = create_proc_read_entry(
PROC_XBUS_WAITFOR_XPDS, 0444,
xbus->proc_xbus_dir,
xbus_read_waitfor_xpds,
xbus);
- if (!poller->proc_xbus_waitfor_xpds) {
+ if (!worker->proc_xbus_waitfor_xpds) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_WAITFOR_XPDS);
goto err;
}
- poller->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+ worker->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
}
#endif
- return poller;
+ return worker;
err:
- poller_destroy(poller);
+ worker_destroy(worker);
return NULL;
}
-/*
- * Sends an xbus_poll() work to the poller workqueue of the given xbus.
- */
-static int poller_dispatch(xbus_t *xbus)
-{
- struct xbus_poller *poller = xbus->poller;
-
- if(!poller) {
- XBUS_ERR(xbus, "missing poller\n");
- return 0;
- }
- /* Initialize the work. (adapt to kernel API changes). */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- INIT_WORK(&poller->xpds_init_work, xbus_poll);
-#else
- INIT_WORK(&poller->xpds_init_work, xbus_poll, poller);
-#endif
- /* Now send it */
- if(!queue_work(poller->wq, &poller->xpds_init_work)) {
- XBUS_ERR(xbus, "Failed to queue xpd initialization work\n");
- return 0;
- }
- return 1;
-}
-
int xbus_activate(xbus_t *xbus)
{
struct xbus_ops *ops;
- struct xbus_poller *poller;
+ struct xbus_workqueue *worker;
BUG_ON(!xbus);
ops = transportops_get(xbus);
BUG_ON(!ops);
- poller = xbus->poller;
- BUG_ON(!poller);
+ worker = xbus->worker;
+ BUG_ON(!worker);
/* Sanity checks */
BUG_ON(!ops->xframe_send_pcm);
BUG_ON(!ops->xframe_send_cmd);
@@ -1086,8 +1020,7 @@ int xbus_activate(xbus_t *xbus)
* Make sure Astribank knows not to send us ticks.
*/
xbus_request_sync(xbus, SYNC_MODE_NONE);
- /* Poll it */
- poller_dispatch(xbus);
+ CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
return 0;
}
@@ -1099,6 +1032,7 @@ void xbus_disconnect(xbus_t *xbus)
XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
xbus_set_command_timer(xbus, 1);
xbus_request_sync(xbus, SYNC_MODE_NONE); /* no more ticks */
+ xbus_sysfs_remove(xbus); /* Device-Model */
for(i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
if(!xpd)
@@ -1146,13 +1080,15 @@ static xbus_t *xbus_alloc(void)
if(i >= MAX_BUSES) {
ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
kfree(xbus);
- return NULL;
+ xbus = NULL;
+ goto out;
}
/* Found empty slot */
xbus->num = i;
init_xbus(i, xbus);
xbus = get_xbus(i);
bus_count++;
+out:
spin_unlock_irqrestore(&xbuses_lock, flags);
return xbus;
}
@@ -1180,7 +1116,6 @@ static void xbus_free(xbus_t *xbus)
debugfs_remove(xbus->debugfs_dir);
}
#endif
- poller_destroy(xbus->poller);
#ifdef CONFIG_PROC_FS
if(xbus->proc_xbus_dir) {
if(xbus->proc_xbus_summary) {
@@ -1222,7 +1157,6 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
{
int err;
xbus_t *xbus = NULL;
- struct xbus_poller *poller;
BUG_ON(!ops);
XBUS_DBG(GENERAL, xbus, "allocate new xbus\n");
@@ -1285,21 +1219,20 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
goto nobus;
}
#endif
- xframe_queue_init(&xbus->command_queue, 10, 200, "command_queue", xbus);
+ xframe_queue_init(&xbus->command_queue, 10, 100, "command_queue", xbus);
xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus);
xframe_queue_init(&xbus->send_pool, 10, 200, "send_pool", xbus);
xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus);
xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus);
tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus);
/*
- * Create poller after /proc/XBUS-?? so the directory exists
+ * Create worker after /proc/XBUS-?? so the directory exists
* before /proc/XBUS-??/waitfor_xpds tries to get created.
*/
- poller = poller_new(xbus);
- if(!poller) {
- ERR("Failed to allocate poller\n");
- xbus_free(xbus);
- return NULL;
+ xbus->worker = worker_new(xbus->num);
+ if(!xbus->worker) {
+ ERR("Failed to allocate worker\n");
+ goto nobus;
}
return xbus;
nobus:
@@ -1315,7 +1248,6 @@ void xbus_remove(xbus_t *xbus)
down_write(&xbus->in_use);
XBUS_INFO(xbus, "[%s] Removing\n", xbus->label);
- xbus_sysfs_remove(xbus); /* Device-Model */
for(i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
@@ -1329,6 +1261,7 @@ void xbus_remove(xbus_t *xbus)
}
xbus->xpds[i] = NULL;
}
+ worker_destroy(xbus->worker);
xbus_free(xbus);
}
@@ -1367,7 +1300,7 @@ static int xbus_fill_proc_queue(char *p, struct xframe_queue *q)
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
xbus_t *xbus;
- struct xbus_poller *poller;
+ struct xbus_workqueue *worker;
unsigned long flags;
int len = 0;
int i = (int)((unsigned long)data);
@@ -1376,7 +1309,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
if(!xbus)
goto out;
spin_lock_irqsave(&xbus->lock, flags);
- poller = xbus->poller;
+ worker = xbus->worker;
len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
@@ -1384,11 +1317,6 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
xbus->label,
(TRANSPORT_RUNNING(xbus)) ? "connected" : "missing"
);
- len += sprintf(page + len, "POLLS: %d/%d\n",
- atomic_read(&poller->count_poll_answers), MAX_XPDS);
- len += sprintf(page + len, "XPDS_READY: %d/%d\n",
- atomic_read(&poller->count_xpds_initialized),
- atomic_read(&poller->count_xpds_to_initialize));
len += sprintf(page + len, "\nxbus_ref_count=%d\n",
atomic_read(&xbus->xbus_ref_count)
);
@@ -1449,7 +1377,7 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
int len = 0;
unsigned long flags;
xbus_t *xbus = data;
- struct xbus_poller *poller;
+ struct xbus_workqueue *worker;
int ret;
if(!xbus)
@@ -1458,30 +1386,28 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
if(!count || off)
goto out;
/*
- * poller is created before /proc/XBUS-??
+ * worker is created before /proc/XBUS-??
* So by now it exists and initialized.
*/
- poller = xbus->poller;
- BUG_ON(!poller);
+ worker = xbus->worker;
+ BUG_ON(!worker);
XBUS_DBG(DEVICES, xbus,
"Waiting for card initialization of %d XPD's max %d seconds\n",
- atomic_read(&poller->count_xpds_to_initialize), INITIALIZATION_TIMEOUT/HZ);
+ worker->num_units,
+ INITIALIZATION_TIMEOUT/HZ);
/*
* when polling is finished xbus_poll():
- * - Unset poller->is_polling
- * - Sets poller->count_xpds_to_initialize.
+ * - Unset worker->is_polling
+ * - Sets worker->count_xpds_to_initialize.
* So we wait until polling is finished (is_polling == 0) and:
* - No poll answers from Astribank (e.g: defective firmware).
* - Or no units to initialize (e.g: mini-AB with only main card).
* - Or we finished initializing all existing units.
* - Or A timeout passed.
*/
- ret = wait_event_interruptible_timeout(poller->wait_for_xpd_initialization,
- !poller->is_polling && (
- atomic_read(&poller->count_poll_answers) == 0 ||
- atomic_read(&poller->count_xpds_to_initialize) == 0 ||
- atomic_read(&poller->count_xpds_initialized) >=
- atomic_read(&poller->count_xpds_to_initialize)),
+ ret = wait_event_interruptible_timeout(
+ worker->wait_for_xpd_initialization,
+ worker->xpds_init_done,
INITIALIZATION_TIMEOUT);
if(ret == 0) {
XBUS_ERR(xbus, "Card Initialization Timeout\n");
@@ -1492,13 +1418,12 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
} else
XBUS_DBG(DEVICES, xbus,
"Finished initialization of %d XPD's in %d seconds.\n",
- atomic_read(&poller->count_xpds_initialized),
+ worker->num_units_initialized,
(INITIALIZATION_TIMEOUT - ret)/HZ);
spin_lock_irqsave(&xbus->lock, flags);
len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n",
xbus->busname,
- atomic_read(&poller->count_xpds_initialized),
- atomic_read(&poller->count_xpds_to_initialize));
+ worker->num_units_initialized, worker->num_units);
spin_unlock_irqrestore(&xbus->lock, flags);
out:
if (len <= off+count)
@@ -1584,7 +1509,7 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
len = max_len;
atomic_set(&xframe->frame_len, len);
memcpy(xframe->packets, pack_start, len); /* FIXME: checksum? */
- dump_xframe("COMMAND", xbus, xframe, print_dbg);
+ dump_xframe("COMMAND", xbus, xframe, debug);
send_cmd_frame(xbus, xframe);
out:
kfree(buf);
@@ -1647,7 +1572,7 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s
init_waitqueue_head(&xbus->transport.transport_unused);
}
-void transport_destroy(xbus_t *xbus)
+static void transport_destroy(xbus_t *xbus)
{
int ret;
@@ -1777,7 +1702,6 @@ EXPORT_SYMBOL(send_cmd_frame);
EXPORT_SYMBOL(xframe_init);
EXPORT_SYMBOL(transportops_get);
EXPORT_SYMBOL(transportops_put);
-EXPORT_SYMBOL(xbus_poller_notify);
EXPORT_SYMBOL(xbus_command_queue_tick);
#ifdef XPP_DEBUGFS
EXPORT_SYMBOL(xbus_log);