summaryrefslogtreecommitdiff
path: root/kernel/xpp/xbus-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/xbus-core.c')
-rw-r--r--kernel/xpp/xbus-core.c833
1 files changed, 503 insertions, 330 deletions
diff --git a/kernel/xpp/xbus-core.c b/kernel/xpp/xbus-core.c
index f458896..9a62f94 100644
--- a/kernel/xpp/xbus-core.c
+++ b/kernel/xpp/xbus-core.c
@@ -50,7 +50,9 @@ static const char rcsid[] = "$Id$";
#define INITIALIZATION_TIMEOUT (90*HZ) /* in jiffies */
#define PROC_XBUSES "xbuses"
#define PROC_XBUS_SUMMARY "summary"
+#ifdef OLD_PROC
#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+#endif
#ifdef PROTOCOL_DEBUG
#define PROC_XBUS_COMMAND "command"
@@ -59,25 +61,41 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
/* Command line parameters */
extern int debug;
+static DEF_PARM(uint, command_queue_length, 800, 0444, "Maximal command queue length");
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);
+#ifdef OLD_PROC
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);
+#endif
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv);
static void transport_destroy(xbus_t *xbus);
/* Data structures */
static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
-static int bus_count = 0;
static struct proc_dir_entry *proc_xbuses = NULL;
static struct xbus_desc {
xbus_t *xbus;
- atomic_t xbus_refcount;
- wait_queue_head_t can_release_xbus;
} xbuses_array[MAX_BUSES];
+const char *xbus_statename(enum xbus_state st)
+{
+ switch(st) {
+ case XBUS_STATE_START: return "START";
+ case XBUS_STATE_IDLE: return "IDLE";
+ case XBUS_STATE_SENT_REQUEST: return "SENT_REQUEST";
+ case XBUS_STATE_RECVD_DESC: return "RECVD_DESC";
+ case XBUS_STATE_READY: return "READY";
+ case XBUS_STATE_DEACTIVATING: return "DEACTIVATING";
+ case XBUS_STATE_DEACTIVATED: return "DEACTIVATED";
+ case XBUS_STATE_DISCONNECTED: return "DISCONNECTED";
+ case XBUS_STATE_FAIL: return "FAIL";
+ }
+ return NULL;
+}
+
static void init_xbus(uint num, xbus_t *xbus)
{
struct xbus_desc *desc;
@@ -85,72 +103,18 @@ static void init_xbus(uint num, xbus_t *xbus)
BUG_ON(num >= ARRAY_SIZE(xbuses_array));
desc = &xbuses_array[num];
desc->xbus = xbus;
- atomic_set(&desc->xbus_refcount, 0);
- init_waitqueue_head(&desc->can_release_xbus);
-}
-
-static int refcount_xbus(uint num)
-{
- BUG_ON(num >= ARRAY_SIZE(xbuses_array));
- return atomic_read(&xbuses_array[num].xbus_refcount);
}
-xbus_t *get_xbus(uint num)
+xbus_t *xbus_num(uint num)
{
struct xbus_desc *desc;
if(num >= ARRAY_SIZE(xbuses_array))
return NULL;
desc = &xbuses_array[num];
- atomic_inc(&desc->xbus_refcount);
- if(!desc->xbus)
- atomic_dec(&desc->xbus_refcount);
return desc->xbus;
}
-void put_xbus(xbus_t *xbus)
-{
- struct xbus_desc *desc;
- int num;
-
- BUG_ON(!xbus);
- num = xbus->num;
- BUG_ON(num >= ARRAY_SIZE(xbuses_array));
- desc = &xbuses_array[num];
- BUG_ON(desc->xbus != xbus);
- if(atomic_dec_and_test(&desc->xbus_refcount)) {
- static int rate_limit;
-
- if((rate_limit++ % 1003) == 0)
- XBUS_DBG(DEVICES, xbus,
- "wake_up(can_release_xbus) (%d)\n", rate_limit);
- wake_up(&desc->can_release_xbus);
- }
-}
-
-static bool __must_check wait_for_xbus_release(uint xbus_num)
-{
- xbus_t *xbus;
- int ret;
-
- xbus = get_xbus(xbus_num);
- if(!xbus) {
- ERR("%s: xbus #%d is already removed. Skip.\n",
- __FUNCTION__, xbus_num);
- return 0;
- }
- put_xbus(xbus);
- DBG(DEVICES, "Waiting... refcount_xbus=%d\n", refcount_xbus(xbus_num));
- ret = wait_event_interruptible(xbuses_array[xbus_num].can_release_xbus,
- refcount_xbus(xbus_num) == 0);
- if(ret) {
- ERR("%s: waiting for xbus #%d interrupted!!!\n",
- __FUNCTION__, xbus_num);
- } else
- DBG(DEVICES, "Waiting for refcount_xbus done.\n");
- return 1;
-}
-
static void initialize_xbuses_array(void)
{
int i;
@@ -171,6 +135,30 @@ static void finalize_xbuses_array(void)
}
}
+xbus_t *get_xbus(const char *msg, xbus_t *xbus)
+{
+ struct device *dev;
+
+ XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
+ msg, refcount_xbus(xbus));
+ dev = get_device(&xbus->astribank);
+ return dev_to_xbus(dev);
+}
+
+void put_xbus(const char *msg, xbus_t *xbus)
+{
+ XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
+ msg, refcount_xbus(xbus));
+ put_device(&xbus->astribank);
+}
+
+int refcount_xbus(xbus_t *xbus)
+{
+ struct kref *kref = &xbus->astribank.kobj.kref;
+
+ return atomic_read(&kref->refcount);
+}
+
/*------------------------- Debugfs Handling -----------------------*/
#ifdef XPP_DEBUGFS
@@ -245,7 +233,7 @@ static struct file_operations debugfs_operations = {
* a bit earlier (2.6.18). If you use such a kernel, Change the
* following test from 2,6,19 to 2,6,18.
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
#define I_PRIVATE(inode) ((inode)->u.generic_ip)
#else
#define I_PRIVATE(inode) ((inode)->i_private)
@@ -314,7 +302,7 @@ static int debugfs_release(struct inode *inode, struct file *file)
BUG_ON(!d->xbus);
XBUS_DBG(GENERAL, d->xbus, "\n");
d->xbus->debugfs_data = NULL;
- kfree(d);
+ KZFREE(d);
module_put(THIS_MODULE);
return 0;
}
@@ -455,23 +443,6 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
spin_unlock_irqrestore(&serialize_dump_xframe, flags);
}
-static bool xbus_ready(const xbus_t *xbus, const char msg[])
-{
- if(!xbus) {
- ERR("null xbus: %s\n", msg);
- return 0;
- }
- if (!TRANSPORT_RUNNING(xbus)) {
- XBUS_ERR(xbus, "%s -- hardware is not ready.", msg);
- return 0;
- }
- if(!xbus->transport.ops) {
- XBUS_ERR(xbus, "%s -- hardware is gone.", msg);
- return 0;
- }
- return 1;
-}
-
/**
*
* Frame is freed:
@@ -484,7 +455,8 @@ int send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
int ret = -ENODEV;
BUG_ON(!xframe);
- if(!xbus_ready(xbus, "Dropped a pcm frame")) {
+ if(!XBUS_IS(xbus, READY)) {
+ XBUS_ERR(xbus, "Dropped a pcm frame -- hardware is not ready.\n");
ret = -ENODEV;
goto error;
}
@@ -509,7 +481,9 @@ static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(!xbus);
BUG_ON(!xframe);
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
- if(!xbus_ready(xbus, "Dropped command before sending")) {
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_ERR(xbus, "Dropped command before sending -- hardware deactivated.\n");
+ dump_xframe("Dropped", xbus, xframe, DBG_ANY);
FREE_SEND_XFRAME(xbus, xframe);
return -ENODEV;
}
@@ -530,18 +504,30 @@ int xbus_command_queue_tick(xbus_t *xbus)
{
xframe_t *frm;
int ret = 0;
+ int packno;
- frm = xframe_dequeue(&xbus->command_queue);
- if(frm) {
+ xbus->command_tick_counter++;
+ xbus->usec_nosend -= 1000; /* That's our budget */
+ for(packno = 0; packno < 3; packno++) {
+ if(xbus->usec_nosend > 0)
+ break;
+ frm = xframe_dequeue(&xbus->command_queue);
+ if(!frm) {
+ wake_up(&xbus->command_queue_empty);
+ break;
+ }
BUG_ON(frm->xframe_magic != XFRAME_MAGIC);
+ xbus->usec_nosend += frm->usec_towait;
ret = really_send_cmd_frame(xbus, frm);
- if(ret < 0)
+ if(ret < 0) {
XBUS_ERR(xbus,
- "Failed to send from command_queue (ret=%d)\n",
- ret);
- XBUS_PUT(xbus);
- } else
- wake_up(&xbus->command_queue_empty);
+ "Failed to send from command_queue (ret=%d)\n",
+ ret);
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
+ }
+ }
+ if(xbus->usec_nosend < 0)
+ xbus->usec_nosend = 0;
return ret;
}
@@ -550,10 +536,9 @@ static void xbus_command_queue_clean(xbus_t *xbus)
xframe_t *frm;
XBUS_DBG(DEVICES, xbus, "count=%d\n", xbus->command_queue.count);
- xframe_queue_disable(&xbus->command_queue);
+ xframe_queue_disable(&xbus->command_queue, 1);
while((frm = xframe_dequeue(&xbus->command_queue)) != NULL) {
FREE_SEND_XFRAME(xbus, frm);
- XBUS_PUT(xbus);
}
}
@@ -577,23 +562,21 @@ int send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
- if(!xbus_ready(xbus, "Dropped command before queueing")) {
- ret = -ENODEV;
- goto err;
- }
- if(!XBUS_GET(xbus)) {
- /* shutting down */
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_ERR(xbus, "Dropped command before queueing -- hardware deactivated.\n");
ret = -ENODEV;
goto err;
}
+ if(debug & DBG_COMMANDS)
+ dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY);
if(!xframe_enqueue(&xbus->command_queue, xframe)) {
if((rate_limit++ % 1003) == 0) {
XBUS_ERR(xbus,
"Dropped command xframe. Cannot enqueue (%d)\n",
rate_limit);
- dump_xframe("send_cmd_frame", xbus, xframe, DBG_ANY);
+ dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY);
}
- XBUS_PUT(xbus);
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
ret = -E2BIG;
goto err;
}
@@ -644,7 +627,7 @@ void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
if(rx_tasklet) {
xframe_enqueue_recv(xbus, xframe);
} else {
- if (likely(TRANSPORT_RUNNING(xbus)))
+ if(likely(!XBUS_IS(xbus, DISCONNECTED)))
xframe_receive(xbus, xframe);
else
FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
@@ -666,75 +649,71 @@ xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit)
return xbus->xpds[XPD_IDX(unit,subunit)];
}
-int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
+int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit)
{
- unsigned int xpd_num = xpd->xbus_idx;
+ unsigned int xpd_num;
unsigned long flags;
- int ret = 0;
- xbus = get_xbus(xbus->num); /* until unregister */
BUG_ON(!xbus);
- XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
- xpd_num, refcount_xbus(xbus->num));
+ xpd_num = XPD_IDX(unit,subunit);
+ XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num);
spin_lock_irqsave(&xbus->lock, flags);
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "Bad xpd_num = %d\n", xpd_num);
- ret = -EINVAL;
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] != NULL) {
xpd_t *other = xbus->xpds[xpd_num];
XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n",
xpd_num, other, other->xpdname);
- ret = -EINVAL;
- goto out;
+ BUG();
}
+ snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
+ MKADDR(&xpd->addr, unit, subunit);
+ xpd->xbus_idx = xpd_num;
xbus->xpds[xpd_num] = xpd;
xpd->xbus = xbus;
- xbus->num_xpds++;
-out:
+ atomic_inc(&xbus->num_xpds);
spin_unlock_irqrestore(&xbus->lock, flags);
- return ret;
+ /* Must be done out of atomic context */
+ if(xpd_device_register(xbus, xpd) < 0) {
+ XPD_ERR(xpd, "%s: xpd_device_register() failed\n", __FUNCTION__);
+ /* FIXME: What to do? */
+ }
+ return 0;
}
-int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
+int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd)
{
unsigned int xpd_num = xpd->xbus_idx;
unsigned long flags;
- int ret = -EINVAL;
- spin_lock_irqsave(&xbus->lock, flags);
- XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
- xpd_num, refcount_xbus(xbus->num));
+ XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num);
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "%s: Bad xpd_num = %d\n", __FUNCTION__, xpd_num);
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] == NULL) {
XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __FUNCTION__, xpd_num);
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] != xpd) {
xpd_t *other = xbus->xpds[xpd_num];
XBUS_ERR(xbus, "%s: slot xpd_num=%d is occupied by %p (%s)\n",
__FUNCTION__, xpd_num, other, other->xpdname);
- goto out;
+ BUG();
}
- xbus->xpds[xpd_num] = NULL;
- xbus->num_xpds--;
+ spin_lock_irqsave(&xbus->lock, flags);
xpd->xbus = NULL;
- put_xbus(xbus); /* we got it in xbus_register_xpd() */
- ret = 0;
-out:
+ xbus->xpds[xpd_num] = NULL;
+ if(atomic_dec_and_test(&xbus->num_xpds))
+ xbus_setstate(xbus, XBUS_STATE_IDLE);
spin_unlock_irqrestore(&xbus->lock, flags);
- return ret;
+ return 0;
}
-/*
- * Called with xbus->worker locked.
- */
static int new_card(xbus_t *xbus,
int unit,
byte type,
@@ -773,7 +752,12 @@ static int new_card(xbus_t *xbus,
BUG_ON(!xops);
xbus->worker->num_units += subunits - 1;
for(i = 0; i < subunits; i++) {
- if(!TRANSPORT_RUNNING(xbus)) {
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_NOTICE(xbus,
+ "Cannot create XPD=%d%d in state %s\n",
+ unit,
+ i,
+ xbus_statename(XBUS_STATE(xbus)));
ret = -ENODEV;
goto out;
}
@@ -782,13 +766,13 @@ static int new_card(xbus_t *xbus,
i,
type,
subtype);
- if(!XBUS_GET(xbus)) {
- XBUS_ERR(xbus, "Aborting creation. Is shutting down.\n");
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_ERR(xbus, "Aborting creation -- In bad state %s\n",
+ xbus_statename(XBUS_STATE(xbus)));
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, "Creation of XPD=%d%d failed %d\n",
unit, i, ret);
@@ -801,44 +785,86 @@ out:
return ret;
}
+static void xbus_release_xpds(xbus_t *xbus)
+{
+ int i;
+
+ XBUS_INFO(xbus, "[%s] Release XPDS\n", xbus->label);
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+
+ if(xpd)
+ put_xpd(__FUNCTION__, xpd); /* taken in xbus_xpd_bind() */
+ }
+}
+
+static int xpd_initialize(xpd_t *xpd)
+{
+ int ret = -ENODEV;
+
+ if(CALL_XMETHOD(card_init, xpd->xbus, xpd) < 0) {
+ XPD_ERR(xpd, "Card Initialization failed\n");
+ goto out;
+ }
+ //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 */
+ if(!xpd_setstate(xpd, XPD_STATE_READY)) {
+ goto out;
+ }
+ XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name);
+ xpd_post_init(xpd);
+ ret = 0;
+out:
+ return ret;
+}
+
static int xbus_initialize(xbus_t *xbus)
{
int unit;
int subunit;
xpd_t *xpd;
+ struct timeval time_start;
+ struct timeval time_end;
+ unsigned long timediff;
+ do_gettimeofday(&time_start);
+ XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n",
+ refcount_xbus(xbus));
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");
+ XBUS_ERR(xbus, "Register Initialization of card #%d failed\n", unit);
goto err;
}
for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ int ret;
+
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");
+ xpd = get_xpd(__FUNCTION__, xpd);
+ if(!xpd) {
+ XBUS_ERR(xbus,
+ "Aborting initialization. XPD-%d%d is gone.\n",
+ unit, subunit);
goto err;
}
- //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);
+ ret = xpd_initialize(xpd);
+ put_xpd(__FUNCTION__, xpd);
+ if(ret < 0)
+ goto err;
}
}
+ do_gettimeofday(&time_end);
+ timediff = usec_diff(&time_end, &time_start);
+ timediff /= 1000*100;
+ XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff/10, timediff%10);
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);
- }
- }
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
return -EINVAL;
}
@@ -848,7 +874,7 @@ err:
* initialized.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-void xbus_populate(struct work_struct *work)
+static void xbus_populate(struct work_struct *work)
{
struct xbus_workqueue *worker = container_of(work, struct xbus_workqueue, xpds_init_work);
#else
@@ -863,10 +889,7 @@ void xbus_populate(void *data)
int ret = 0;
xbus = worker->xbus;
- if(!XBUS_GET(xbus)) {
- XBUS_NOTICE(xbus, "Shutting down, aboring initialization\n");
- return;
- }
+ 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) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
@@ -889,62 +912,127 @@ void xbus_populate(void *data)
break;
}
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);
+ if(xbus_initialize(xbus) < 0) {
+ XBUS_NOTICE(xbus, "Initialization failed. Leave unused. refcount_xbus=%d\n",
+ refcount_xbus(xbus));
+ goto failed;
}
- wake_up(&worker->wait_for_xpd_initialization);
+ if(!xbus_setstate(xbus, XBUS_STATE_READY)) {
+ XBUS_NOTICE(xbus, "Illegal transition. Leave unused. refcount_xbus=%d\n",
+ refcount_xbus(xbus));
+ goto failed;
+ }
+ worker->xpds_init_done = 1;
/*
* Now request Astribank to start self_ticking.
* This is the last initialization command. So
* all others will reach the device before it.
*/
xbus_request_sync(xbus, SYNC_MODE_PLL);
- elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */
- put_xbus(xbus); /* taken in AB_DESCRIPTION */
- XBUS_PUT(xbus);
+ 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);
+ XBUS_DBG(DEVICES, xbus, "populate release\n");
+ up(&xbus->in_worker);
+ return;
+failed:
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
+ goto out;
}
-static void worker_destroy(struct xbus_workqueue *worker)
+int xbus_process_worker(xbus_t *xbus)
{
- xbus_t *xbus;
+ struct xbus_workqueue *worker = xbus->worker;
+
+ if(!xbus) {
+ ERR("%s: xbus gone -- skip initialization\n", __FUNCTION__);
+ return 0;
+ }
+ if(down_trylock(&xbus->in_worker)) {
+ ERR("%s: xbus is disconnected -- skip initialization\n", __FUNCTION__);
+ return 0;
+ }
+ XBUS_DBG(DEVICES, xbus, "\n");
+ /* Initialize the work. (adapt to kernel API changes). */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ INIT_WORK(&worker->xpds_init_work, xbus_populate);
+#else
+ INIT_WORK(&worker->xpds_init_work, xbus_populate, worker);
+#endif
+ BUG_ON(!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);
+ return 0;
+ }
+ return 1;
+}
+
+static void worker_reset(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";
- if(!worker)
- return;
+ BUG_ON(!worker);
+ DBG(DEVICES, "%s\n", name);
+ if(!worker->xpds_init_done) {
+ NOTICE("%s: worker(%s)->xpds_init_done=%d\n",
+ __FUNCTION__, name, worker->xpds_init_done);
+ }
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);
BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
list_del(card);
- kfree(card_desc);
+ KZFREE(card_desc);
}
+ worker->xpds_init_done = 0;
+ worker->num_units = 0;
+ worker->num_units_initialized = 0;
spin_unlock_irqrestore(&worker->worker_lock, flags);
+ wake_up(&worker->wait_for_xpd_initialization);
+}
+
+static void worker_destroy(struct xbus_workqueue *worker)
+{
+ xbus_t *xbus;
+
+ 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");
+ }
#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;
}
#endif
+#endif
XBUS_DBG(DEVICES, xbus, "detach worker\n");
xbus->worker = NULL;
+ KZFREE(worker);
+ put_xbus(__FUNCTION__, xbus); /* got from worker_new() */
}
- 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); /* Taken in worker_new() */
- KZFREE(worker);
}
/*
@@ -952,29 +1040,27 @@ 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 xbus_num)
+static struct xbus_workqueue *worker_new(int xbusno)
{
struct xbus_workqueue *worker;
xbus_t *xbus;
- xbus = get_xbus(xbus_num); /* release in worker_destroy */
+ if((xbus = xbus_num(xbusno)) == NULL)
+ return NULL;
+ get_xbus(__FUNCTION__, xbus); /* return in worker_destroy() */
BUG_ON(xbus->busname[0] == '\0'); /* No name? */
- BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
+ BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
XBUS_DBG(DEVICES, xbus, "\n");
worker = KZALLOC(sizeof(*worker), GFP_KERNEL);
if(!worker)
goto err;
- worker->xbus = xbus;
/* 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 = create_singlethread_workqueue(xbus->busname);
- if(!worker->wq) {
- XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
- goto err;
- }
+ worker->xbus = xbus;
#ifdef CONFIG_PROC_FS
+#ifdef OLD_PROC
if(xbus->proc_xbus_dir) {
worker->proc_xbus_waitfor_xpds = create_proc_read_entry(
PROC_XBUS_WAITFOR_XPDS, 0444,
@@ -988,18 +1074,118 @@ static struct xbus_workqueue *worker_new(int xbus_num)
worker->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
}
#endif
+#endif
+ worker->wq = create_singlethread_workqueue(xbus->busname);
+ if(!worker->wq) {
+ XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
+ goto err;
+ }
return worker;
err:
worker_destroy(worker);
return NULL;
}
+bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate)
+{
+ unsigned long flags;
+ bool ret = 0;
+ int state_flip = 0;
+
+ spin_lock_irqsave(&xbus->transport.state_lock, flags);
+ if(newstate == XBUS_STATE(xbus)) {
+ XBUS_DBG(DEVICES, xbus, "stay at %s\n",
+ xbus_statename(newstate));
+ goto out;
+ }
+ /* Sanity tests */
+ switch(newstate) {
+ case XBUS_STATE_START:
+ goto bad_state;
+ case XBUS_STATE_IDLE:
+ if(!XBUS_IS(xbus, START) &&
+ !XBUS_IS(xbus, DEACTIVATED))
+ goto bad_state;
+ break;
+ case XBUS_STATE_SENT_REQUEST:
+ if(!XBUS_IS(xbus, IDLE) &&
+ !XBUS_IS(xbus, SENT_REQUEST))
+ goto bad_state;
+ break;
+ case XBUS_STATE_RECVD_DESC:
+ if(!XBUS_IS(xbus, SENT_REQUEST))
+ goto bad_state;
+ break;
+ case XBUS_STATE_READY:
+ if(!XBUS_IS(xbus, RECVD_DESC))
+ goto bad_state;
+ state_flip = 1; /* We are good */
+ break;
+ case XBUS_STATE_DEACTIVATING:
+#if 0
+ if(XBUS_IS(xbus, DEACTIVATED) || XBUS_IS(xbus, DISCONNECTED))
+ goto bad_state;
+#endif
+ break;
+ case XBUS_STATE_DEACTIVATED:
+ if(!XBUS_IS(xbus, DEACTIVATING))
+ goto bad_state;
+ break;
+ case XBUS_STATE_DISCONNECTED:
+ break;
+ case XBUS_STATE_FAIL:
+ if(XBUS_IS(xbus, DEACTIVATING) || XBUS_IS(xbus, DEACTIVATED) || XBUS_IS(xbus, DISCONNECTED))
+ goto bad_state;
+ break;
+ default:
+ XBUS_NOTICE(xbus, "%s: unknown state %d\n", __FUNCTION__, newstate);
+ goto out;
+ }
+ /* All good */
+ XBUS_DBG(DEVICES, xbus, "%s -> %s\n",
+ xbus_statename(XBUS_STATE(xbus)),
+ xbus_statename(newstate));
+ if(xbus->transport.xbus_state == XBUS_STATE_READY && newstate != XBUS_STATE_READY)
+ state_flip = -1; /* We became bad */
+ xbus->transport.xbus_state = newstate;
+ ret = 1;
+out:
+ spin_unlock_irqrestore(&xbus->transport.state_lock, flags);
+ /* Should be sent out of spinlocks */
+ if(state_flip > 0)
+ astribank_uevent_send(xbus, KOBJ_ONLINE);
+ else if(state_flip < 0)
+ astribank_uevent_send(xbus, KOBJ_OFFLINE);
+ return ret;
+bad_state:
+ XBUS_NOTICE(xbus, "Bad state transition %s -> %s ignored.\n",
+ xbus_statename(XBUS_STATE(xbus)),
+ xbus_statename(newstate));
+ goto out;
+}
+
int xbus_activate(xbus_t *xbus)
{
+ XBUS_INFO(xbus, "[%s] Activating\n", xbus->label);
+ xpp_drift_init(xbus);
+ xbus_set_command_timer(xbus, 1);
+ xframe_queue_disable(&xbus->command_queue, 0);
+ xbus_setstate(xbus, XBUS_STATE_IDLE); /* must be done after transport is valid */
+ CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
+ /*
+ * Make sure Astribank knows not to send us ticks.
+ */
+ xbus_request_sync(xbus, SYNC_MODE_NONE);
+ return 0;
+}
+
+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;
@@ -1009,64 +1195,56 @@ int xbus_activate(xbus_t *xbus)
BUG_ON(!ops->xframe_send_cmd);
BUG_ON(!ops->alloc_xframe);
BUG_ON(!ops->free_xframe);
- xpp_drift_init(xbus);
- /*
- * We start with timer based ticking
- */
- xbus_set_command_timer(xbus, 1);
- xbus->transport.transport_running = 1; /* must be done after transport is valid */
- XBUS_INFO(xbus, "[%s] Activating\n", xbus->label);
- /*
- * Make sure Astribank knows not to send us ticks.
- */
- xbus_request_sync(xbus, SYNC_MODE_NONE);
- CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
+ xbus_activate(xbus);
return 0;
}
-void xbus_disconnect(xbus_t *xbus)
+void xbus_deactivate(xbus_t *xbus, bool is_disconnected)
{
- int i;
-
BUG_ON(!xbus);
- XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
- xbus_set_command_timer(xbus, 1);
+ XBUS_INFO(xbus, "[%s] Deactivating\n", xbus->label);
+ if(!xbus_setstate(xbus, XBUS_STATE_DEACTIVATING))
+ return;
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)
- continue;
- if(xpd->xbus_idx != i) {
- XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
- continue;
- }
- xpd_disconnect(xpd);
- }
- XBUS_DBG(DEVICES, xbus, "Deactivating\n");
- tasklet_kill(&xbus->receive_tasklet);
- xframe_queue_clear(&xbus->receive_queue);
+ xbus_request_removal(xbus);
+ XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label);
xbus_command_queue_clean(xbus);
xbus_command_queue_waitempty(xbus);
- del_timer_sync(&xbus->command_timer);
+ xbus_setstate(xbus, XBUS_STATE_DEACTIVATED);
+ worker_reset(xbus->worker);
+ xbus_release_xpds(xbus);
+ if(!is_disconnected)
+ xbus_setstate(xbus, XBUS_STATE_IDLE);
+ elect_syncer("deactivate");
+}
+
+void xbus_disconnect(xbus_t *xbus)
+{
+ XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
+ BUG_ON(!xbus);
+ xbus_deactivate(xbus, 1);
+ xbus_command_queue_clean(xbus);
+ xbus_command_queue_waitempty(xbus);
+ tasklet_kill(&xbus->receive_tasklet);
+ xframe_queue_clear(&xbus->receive_queue);
xframe_queue_clear(&xbus->send_pool);
xframe_queue_clear(&xbus->receive_pool);
xframe_queue_clear(&xbus->pcm_tospan);
+ xbus_setstate(xbus, XBUS_STATE_DISCONNECTED);
+ del_timer_sync(&xbus->command_timer);
transportops_put(xbus);
transport_destroy(xbus);
- elect_syncer("disconnect");
- XBUS_DBG(DEVICES, xbus, "Deactivated (refcount_xbus=%d)\n", refcount_xbus(xbus->num));
- if(atomic_dec_and_test(&xbus->xbus_ref_count)) {
- XBUS_DBG(DEVICES, xbus, "Going to remove XBUS\n");
- xbus_remove(xbus);
- }
+ worker_destroy(xbus->worker);
+ XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n",
+ refcount_xbus(xbus));
+ xbus_sysfs_remove(xbus); /* Device-Model */
}
static xbus_t *xbus_alloc(void)
{
unsigned long flags;
- xbus_t *xbus;
- int i;
+ xbus_t *xbus;
+ int i;
xbus = KZALLOC(sizeof(xbus_t), GFP_KERNEL);
if(!xbus) {
@@ -1079,28 +1257,27 @@ static xbus_t *xbus_alloc(void)
break;
if(i >= MAX_BUSES) {
ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
- kfree(xbus);
+ KZFREE(xbus);
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;
}
-static void xbus_free(xbus_t *xbus)
+void xbus_free(xbus_t *xbus)
{
unsigned long flags;
uint num;
if(!xbus)
return;
+ XBUS_DBG(DEVICES, xbus, "Free\n");
spin_lock_irqsave(&xbuses_lock, flags);
num = xbus->num;
BUG_ON(!xbuses_array[num].xbus);
@@ -1136,46 +1313,42 @@ static void xbus_free(xbus_t *xbus)
}
#endif
spin_lock_irqsave(&xbuses_lock, flags);
- /*
- * Return to xbus reference counts:
- * - One from our caller: transport disconnect or xpp_close()
- * - One from xbus_alloc()
- */
- put_xbus(xbus);
- put_xbus(xbus);
- if(!wait_for_xbus_release(xbus->num))
- BUG(); /* Let's see what happens next... */
- bus_count--;
- XBUS_DBG(DEVICES, xbus, "Going to free... refcount_xbus=%d\n", refcount_xbus(num));
- BUG_ON(refcount_xbus(num) != 0);
+ XBUS_DBG(DEVICES, xbus, "Going to free...\n");
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
KZFREE(xbus);
}
-xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
+xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv)
{
int err;
xbus_t *xbus = NULL;
BUG_ON(!ops);
- XBUS_DBG(GENERAL, xbus, "allocate new xbus\n");
xbus = xbus_alloc();
- if(!xbus)
+ if(!xbus) {
+ ERR("%s: Failed allocating new xbus\n", __FUNCTION__);
+ module_put(THIS_MODULE);
return NULL;
- transport_init(xbus, ops, max_send_size, priv);
- spin_lock_init(&xbus->lock);
- atomic_set(&xbus->xbus_ref_count, 1); /* a single ref */
+ }
snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
+ XBUS_DBG(DEVICES, xbus, "\n");
+ transport_init(xbus, ops, max_send_size, transport_device, priv);
+ 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;
- xbus->num_xpds = 0;
+ atomic_set(&xbus->num_xpds, 0);
xbus->sync_mode = SYNC_MODE_NONE;
- init_rwsem(&xbus->in_use);
+ err = xbus_sysfs_create(xbus);
+ if(err) {
+ XBUS_ERR(xbus, "SYSFS creation failed: %d\n", err);
+ goto nobus;
+ }
xbus_reset_counters(xbus);
#ifdef CONFIG_PROC_FS
XBUS_DBG(PROC, xbus, "Creating xbus proc directory\n");
@@ -1219,9 +1392,9 @@ 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, command_queue_length, "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->send_pool, 10, 100, "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);
@@ -1240,31 +1413,6 @@ nobus:
return NULL;
}
-void xbus_remove(xbus_t *xbus)
-{
- int i;
-
- BUG_ON(TRANSPORT_RUNNING(xbus));
- down_write(&xbus->in_use);
-
- XBUS_INFO(xbus, "[%s] Removing\n", xbus->label);
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
-
- if(xpd) {
- if(xpd->xbus_idx != i) {
- XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
- continue;
- }
- XBUS_DBG(DEVICES, xbus, " Removing xpd #%d\n", i);
- xpd_remove(xpd);
- }
- xbus->xpds[i] = NULL;
- }
- worker_destroy(xbus->worker);
- xbus_free(xbus);
-}
-
/*------------------------- Proc handling --------------------------*/
void xbus_reset_counters(xbus_t *xbus)
@@ -1305,21 +1453,19 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
int len = 0;
int i = (int)((unsigned long)data);
- xbus = get_xbus(i);
+ xbus = xbus_num(i);
if(!xbus)
goto out;
+ xbus = get_xbus(__FUNCTION__, xbus); /* until end of xbus_read_proc */
spin_lock_irqsave(&xbus->lock, flags);
worker = xbus->worker;
len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
- xbus->location,
+ xbus->connector,
xbus->label,
- (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing"
+ (!XBUS_IS(xbus, DISCONNECTED)) ? "connected" : "missing"
);
- len += sprintf(page + len, "\nxbus_ref_count=%d\n",
- atomic_read(&xbus->xbus_ref_count)
- );
len += xbus_fill_proc_queue(page + len, &xbus->send_pool);
len += xbus_fill_proc_queue(page + len, &xbus->receive_pool);
len += xbus_fill_proc_queue(page + len, &xbus->command_queue);
@@ -1336,6 +1482,8 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
}
len += sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n",
xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec);
+ len += sprintf(page + len, "command_tick: %d\n", xbus->command_tick_counter);
+ len += sprintf(page + len, "usec_nosend: %d\n", xbus->usec_nosend);
len += sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n",
atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count);
len += sprintf(page + len, "max_rx_process = %2ld.%ld ms\n",
@@ -1358,7 +1506,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
}
len += sprintf(page + len, "<-- len=%d\n", len);
spin_unlock_irqrestore(&xbus->lock, flags);
- put_xbus(xbus);
+ put_xbus(__FUNCTION__, xbus); /* from xbus_read_proc() */
out:
if (len <= off+count)
*eof = 1;
@@ -1372,59 +1520,86 @@ out:
}
-static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
+static bool xpds_done(xbus_t *xbus)
{
- int len = 0;
- unsigned long flags;
- xbus_t *xbus = data;
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)
+ return 1; /* All good */
+ /* Keep waiting */
+ return 0;
+}
+
+int waitfor_xpds(xbus_t *xbus, char *buf)
+{
+ struct xbus_workqueue *worker;
+ unsigned long flags;
int ret;
+ int len = 0;
- if(!xbus)
- goto out;
- /* first handle special cases */
- if(!count || off)
- goto out;
/*
- * worker is created before /proc/XBUS-??
+ * FIXME: worker is created before ?????
* So by now it exists and initialized.
*/
+ xbus = get_xbus(__FUNCTION__, xbus); /* until end of waitfor_xpds_show() */
+ if(!xbus)
+ return -ENODEV;
worker = xbus->worker;
BUG_ON(!worker);
XBUS_DBG(DEVICES, xbus,
"Waiting for card initialization of %d XPD's max %d seconds\n",
worker->num_units,
INITIALIZATION_TIMEOUT/HZ);
- /*
- * when polling is finished xbus_poll():
- * - 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(
worker->wait_for_xpd_initialization,
- worker->xpds_init_done,
+ xpds_done(xbus),
INITIALIZATION_TIMEOUT);
if(ret == 0) {
XBUS_ERR(xbus, "Card Initialization Timeout\n");
- return ret;
+ len = -ETIMEDOUT;
+ goto out;
} else if(ret < 0) {
XBUS_ERR(xbus, "Card Initialization Interrupted %d\n", ret);
- return ret;
+ len = ret;
+ goto out;
} else
XBUS_DBG(DEVICES, xbus,
"Finished initialization of %d XPD's in %d seconds.\n",
worker->num_units_initialized,
(INITIALIZATION_TIMEOUT - ret)/HZ);
- spin_lock_irqsave(&xbus->lock, flags);
- len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n",
+ if(XBUS_IS(xbus, FAIL)) {
+ len += sprintf(buf, "FAILED: %s\n", xbus->busname);
+ } else {
+ spin_lock_irqsave(&xbus->lock, flags);
+ len += sprintf(buf, "XPDS_READY: %s: %d/%d\n",
xbus->busname,
worker->num_units_initialized, worker->num_units);
- spin_unlock_irqrestore(&xbus->lock, flags);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ }
+out:
+ put_xbus(__FUNCTION__, xbus); /* from start of waitfor_xpds_show() */
+ return len;
+}
+
+#ifdef OLD_PROC
+static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ xbus_t *xbus = data;
+
+ if(!xbus)
+ goto out;
+ XBUS_NOTICE(xbus, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
+ /* first handle special cases */
+ if(!count || off)
+ goto out;
+ len = waitfor_xpds(xbus, page);
out:
if (len <= off+count)
*eof = 1;
@@ -1437,6 +1612,7 @@ out:
return len;
}
+#endif
#ifdef PROTOCOL_DEBUG
static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
@@ -1526,17 +1702,15 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
spin_lock_irqsave(&xbuses_lock, flags);
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
+ xbus_t *xbus = xbus_num(i);
if(xbus) {
- len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s REFCOUNT=%d\n",
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
- xbus->location,
+ xbus->connector,
xbus->label,
- (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing",
- refcount_xbus(i) - 1
+ (!XBUS_IS(xbus, DISCONNECTED)) ? "connected" : "missing"
);
- put_xbus(xbus);
}
}
#if 0
@@ -1556,7 +1730,7 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
}
#endif
-static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv)
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv)
{
BUG_ON(!xbus);
BUG_ON(!ops);
@@ -1566,7 +1740,10 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s
BUG_ON(!ops->free_xframe);
xbus->transport.ops = ops;
xbus->transport.max_send_size = max_send_size;
+ xbus->transport.transport_device = transport_device;
xbus->transport.priv = priv;
+ xbus->transport.xbus_state = XBUS_STATE_START;
+ spin_lock_init(&xbus->transport.state_lock);
spin_lock_init(&xbus->transport.lock);
atomic_set(&xbus->transport.transport_refcount, 0);
init_waitqueue_head(&xbus->transport.transport_unused);
@@ -1577,7 +1754,6 @@ static void transport_destroy(xbus_t *xbus)
int ret;
BUG_ON(!xbus);
- xbus->transport.transport_running = 0;
XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n",
atomic_read(&xbus->transport.transport_refcount));
ret = wait_event_interruptible(xbus->transport.transport_unused,
@@ -1660,7 +1836,7 @@ int __init xbus_core_init(void)
goto err;
}
#endif
- if((ret = register_xpp_bus()) < 0)
+ if((ret = xpp_driver_init()) < 0)
goto err;
return 0;
err:
@@ -1673,25 +1849,22 @@ void xbus_core_shutdown(void)
{
int i;
- for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
-
- if(xbus) {
- xbus_remove(xbus);
- }
- }
- BUG_ON(bus_count);
- unregister_xpp_bus();
+ for(i = 0; i < MAX_BUSES; i++)
+ BUG_ON(xbus_num(i));
xbus_core_cleanup();
+ xpp_driver_exit();
}
EXPORT_SYMBOL(xpd_of);
EXPORT_SYMBOL(xpd_byaddr);
-EXPORT_SYMBOL(get_xbus);
-EXPORT_SYMBOL(put_xbus);
+EXPORT_SYMBOL(xbus_num);
+EXPORT_SYMBOL(xbus_setstate);
+EXPORT_SYMBOL(xbus_statename);
EXPORT_SYMBOL(xbus_new);
-EXPORT_SYMBOL(xbus_remove);
+EXPORT_SYMBOL(xbus_free);
+EXPORT_SYMBOL(xbus_connect);
EXPORT_SYMBOL(xbus_activate);
+EXPORT_SYMBOL(xbus_deactivate);
EXPORT_SYMBOL(xbus_disconnect);
EXPORT_SYMBOL(xbus_receive_xframe);
EXPORT_SYMBOL(xbus_reset_counters);