summaryrefslogtreecommitdiff
path: root/xpp/xbus-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xbus-core.c')
-rw-r--r--xpp/xbus-core.c931
1 files changed, 663 insertions, 268 deletions
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
index 3935571..00acc3e 100644
--- a/xpp/xbus-core.c
+++ b/xpp/xbus-core.c
@@ -59,25 +59,138 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
/* 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");
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 int read_proc_xmitter(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 xbus_t *xbuses_array[MAX_BUSES] = {};
static int bus_count = 0;
static struct proc_dir_entry *proc_xbuses = NULL;
-/*
- * Command Statistics
- */
-uint command_count;
-ulong sum_latency;
-struct proc_dir_entry *proc_commands;
-#define PROC_CMDS "cmds"
+static struct xbus_desc {
+ xbus_t *xbus;
+ atomic_t xbus_refcount;
+ wait_queue_head_t can_release_xbus;
+} xbuses_array[MAX_BUSES];
+
+static void init_xbus(uint num, xbus_t *xbus)
+{
+ struct xbus_desc *desc;
+
+ 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);
+}
+
+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)
+{
+ 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);
+ }
+}
+
+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;
+
+ for(i = 0; i < ARRAY_SIZE(xbuses_array); i++)
+ init_xbus(i, NULL);
+}
+
+static void finalize_xbuses_array(void)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(xbuses_array); i++) {
+ if(xbuses_array[i].xbus != NULL) {
+ ERR("%s: xbus #%d is not NULL\n", __FUNCTION__, i);
+ BUG();
+ }
+ }
+}
/*------------------------- Debugfs Handling -----------------------*/
#ifdef XPP_DEBUGFS
@@ -230,31 +343,18 @@ static int debugfs_release(struct inode *inode, struct file *file)
#endif
/*------------------------- Frame Handling ------------------------*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-static kmem_cache_t *xframes_cache = NULL;
-#else
-static struct kmem_cache *xframes_cache = NULL;
-#endif
-xframe_t *xbus_xframe_new(xbus_t *xbus, gfp_t flags)
+void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv)
{
- xframe_t *frm;
-
- frm = kmem_cache_alloc(xframes_cache, flags);
- if(!frm)
- return NULL;
- memset(frm, 0, sizeof(xframe_t) + XFRAME_DATASIZE);
- INIT_LIST_HEAD(&frm->frame_list);
- atomic_set(&frm->frame_len, 0);
- frm->xbus = xbus;
- do_gettimeofday(&frm->tv_created);
- frm->packets = (byte *)frm + sizeof(xframe_t);
- return frm;
-}
-
-void xbus_xframe_free(xbus_t *xbus, xframe_t *p)
-{
- kmem_cache_free(xframes_cache, p);
+ memset(xframe, 0, sizeof(*xframe));
+ INIT_LIST_HEAD(&xframe->frame_list);
+ xframe->priv = priv;
+ xframe->xbus = xbus;
+ xframe->packets = xframe->first_free = buf;
+ xframe->frame_maxlen = maxsize;
+ atomic_set(&xframe->frame_len, 0);
+ do_gettimeofday(&xframe->tv_created);
+ xframe->xframe_magic = XFRAME_MAGIC;
}
/*
@@ -268,7 +368,7 @@ void xbus_xframe_free(xbus_t *xbus, xframe_t *p)
*/
xpacket_t *xframe_next_packet(xframe_t *frm, int len)
{
- int newlen = atomic_read(&frm->frame_len);
+ int newlen = XFRAME_LEN(frm);
newlen += len;
// DBG(GENERAL, "len=%d, newlen=%d, frm->frame_len=%d\n", len, newlen, XFRAME_LEN(frm));
@@ -284,7 +384,7 @@ 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 = 1;
+ int print_dbg = DBG_ANY; /* mask global print_dbg */
for(i = 0; i < len; i++)
DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]);
@@ -292,7 +392,7 @@ static void do_hexdump(const char msg[], byte *data, uint16_t len)
void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
{
- const uint16_t frame_len = XFRAME_LEN(xframe);
+ const uint16_t frm_len = XFRAME_LEN(xframe);
xpacket_t *pack;
uint16_t pos = 0;
uint16_t nextpos;
@@ -300,21 +400,26 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
bool do_print;
unsigned long flags;
+ if(xframe->xframe_magic != XFRAME_MAGIC) {
+ XBUS_ERR(xbus, "%s: bad xframe_magic %lX\n",
+ __FUNCTION__, xframe->xframe_magic);
+ return;
+ }
spin_lock_irqsave(&serialize_dump_xframe, flags);
do {
- if(pos >= XFRAME_DATASIZE) {
+ if(pos >= xbus->transport.max_send_size) {
if(printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: xframe overflow (%d bytes)\n",
- msg, frame_len);
- do_hexdump(msg, xframe->packets, frame_len);
+ msg, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
}
break;
}
- if(pos > frame_len) {
+ if(pos > frm_len) {
if(printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: packet overflow pos=%d frame_len=%d\n",
- msg, pos, frame_len);
- do_hexdump(msg, xframe->packets, frame_len);
+ msg, pos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
}
break;
}
@@ -322,17 +427,17 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
if(XPACKET_LEN(pack) <= 0) {
if(printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: xframe -- bad packet_len=%d pos=%d frame_len=%d\n",
- msg, XPACKET_LEN(pack), pos, frame_len);
- do_hexdump(msg, xframe->packets, frame_len);
+ msg, XPACKET_LEN(pack), pos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
}
break;
}
nextpos = pos + XPACKET_LEN(pack);
- if(nextpos > frame_len) {
+ if(nextpos > frm_len) {
if(printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: packet overflow nextpos=%d frame_len=%d\n",
- msg, nextpos, frame_len);
- do_hexdump(msg, xframe->packets, frame_len);
+ msg, nextpos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
}
break;
}
@@ -349,7 +454,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
if(do_print) {
if(num == 1) {
XBUS_DBG(ANY, xbus, "%s: frame_len=%d. %s\n",
- msg, frame_len,
+ msg, frm_len,
(XPACKET_IS_PCM(pack))
? "(IS_PCM)"
: "");
@@ -364,73 +469,207 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
}
num++;
pos = nextpos;
- if(pos >= frame_len)
+ if(pos >= frm_len)
break;
} while(1);
spin_unlock_irqrestore(&serialize_dump_xframe, flags);
}
+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:
* - In case of error, by this function.
* - Otherwise, by the underlying sending mechanism
*/
-int xframe_send(xbus_t *xbus, xframe_t *xframe)
+int send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
{
+ struct xbus_ops *ops;
int ret = -ENODEV;
- if(!xframe) {
- DBG(GENERAL, "null xframe\n");
- return -EINVAL;
- }
- if(!xbus) {
- DBG(GENERAL, "null xbus\n");
- ret = -EINVAL;
- goto error;
- }
- if (!xbus->hardware_exists) {
- XBUS_DBG(GENERAL, xbus, "Dropped a xframe -- NO HARDWARE.");
+ BUG_ON(!xframe);
+ if(!xbus_ready(xbus, "Dropped a pcm frame")) {
ret = -ENODEV;
goto error;
}
- if(down_read_trylock(&xbus->in_use)) {
- ret = xbus->ops->xframe_send(xbus, xframe);
+ ops = transportops_get(xbus);
+ BUG_ON(!ops);
+ ret = ops->xframe_send_pcm(xbus, xframe);
+ transportops_put(xbus);
+ if(ret)
XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe);
- up_read(&xbus->in_use);
- } else {
- XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is in_use\n");
- }
return ret;
error:
- xbus->ops->xframe_free(xbus, xframe);
+ FREE_SEND_XFRAME(xbus, xframe);
+ return ret;
+}
+
+static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
+{
+ struct xbus_ops *ops;
+ int ret;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xframe);
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ if(!xbus_ready(xbus, "Dropped command before sending")) {
+ FREE_SEND_XFRAME(xbus, xframe);
+ return -ENODEV;
+ }
+ ops = transportops_get(xbus);
+ BUG_ON(!ops);
+ ret = ops->xframe_send_cmd(xbus, xframe);
+ transportops_put(xbus);
+ if(ret == 0) {
+ XBUS_COUNTER(xbus, TX_CMD)++;
+ XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe);
+ }
+ return ret;
+}
+
+int xbus_command_queue_tick(xbus_t *xbus)
+{
+ xframe_t *frm;
+ int ret = 0;
+
+ frm = xframe_dequeue(&xbus->command_queue);
+ if(frm) {
+ BUG_ON(frm->xframe_magic != XFRAME_MAGIC);
+ ret = really_send_cmd_frame(xbus, frm);
+ 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);
+ return ret;
+}
+
+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);
+ while((frm = xframe_dequeue(&xbus->command_queue)) != NULL) {
+ FREE_SEND_XFRAME(xbus, frm);
+ XBUS_PUT(xbus);
+ }
+}
+
+static int xbus_command_queue_waitempty(xbus_t *xbus)
+{
+ int ret;
+
+ XBUS_DBG(DEVICES, xbus, "Waiting for command_queue to empty\n");
+ ret = wait_event_interruptible(xbus->command_queue_empty,
+ xframe_queue_count(&xbus->command_queue) == 0);
+ if(ret) {
+ XBUS_ERR(xbus, "waiting for command_queue interrupted!!!\n");
+ }
return ret;
}
int send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
{
- struct timeval now;
- struct timeval *created = &xframe->tv_created;
- ulong usec_diff;
+ static int rate_limit;
+ const char *msg = "";
+ int ret = 0;
- command_count++;
- do_gettimeofday(&now);
- usec_diff =
- (now.tv_sec - created->tv_sec) * 1000000 +
- (now.tv_usec - created->tv_usec);
- sum_latency += usec_diff;
- return xframe_send(xbus, xframe);
+
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ if(!xbus_ready(xbus, "Dropped command before queueing")) {
+ ret = -ENODEV;
+ goto err;
+ }
+ if(!XBUS_GET(xbus)) {
+ msg = "Dropped command xframe. Is shutting down.";
+ ret = -ENODEV;
+ goto err;
+ }
+ if(!xframe_enqueue(&xbus->command_queue, xframe)) {
+ XBUS_PUT(xbus);
+ msg = "Dropped command xframe. Cannot enqueue.";
+ ret = -E2BIG;
+ goto err;
+ }
+ return 0;
+err:
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_ERR(xbus, "%s\n", msg);
+ dump_xframe("send_cmd_frame", xbus, xframe);
+ }
+ FREE_SEND_XFRAME(xbus, xframe);
+ return ret;
}
-/*------------------------- Bus Management -------------------------*/
-xbus_t *xbus_of(int xbus_num)
+/*------------------------- Receive Tasklet Handling ---------------*/
+
+static void xframe_enqueue_recv(xbus_t *xbus, xframe_t *xframe)
{
- if(xbus_num < 0 || xbus_num >= MAX_BUSES)
- return NULL;
- return xbuses_array[xbus_num];
+ int cpu = smp_processor_id();
+
+ BUG_ON(!xbus);
+ xbus->cpu_rcv_intr[cpu]++;
+ if(!xframe_enqueue(&xbus->receive_queue, xframe)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XBUS_ERR(xbus, "Failed to enqueue for receive_tasklet (%d)\n", rate_limit);
+ FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
+ return;
+ }
+ tasklet_schedule(&xbus->receive_tasklet);
+}
+
+/*
+ * process frames in the receive_queue in a tasklet
+ */
+static void receive_tasklet_func(unsigned long data)
+{
+ xbus_t *xbus = (xbus_t *)data;
+ xframe_t *xframe = NULL;
+ int cpu = smp_processor_id();
+
+ BUG_ON(!xbus);
+ xbus->cpu_rcv_tasklet[cpu]++;
+ while((xframe = xframe_dequeue(&xbus->receive_queue)) != NULL) {
+ xframe_receive(xbus, xframe);
+ }
+}
+
+void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
+{
+ BUG_ON(!xbus);
+ if(rx_tasklet) {
+ xframe_enqueue_recv(xbus, xframe);
+ } else {
+ if (likely(TRANSPORT_RUNNING(xbus)))
+ xframe_receive(xbus, xframe);
+ else
+ FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
+ }
}
+/*------------------------- Bus Management -------------------------*/
xpd_t *xpd_of(const xbus_t *xbus, int xpd_num)
{
if(!VALID_XPD_NUM(xpd_num))
@@ -451,6 +690,10 @@ int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
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));
spin_lock_irqsave(&xbus->lock, flags);
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "Bad xpd_num = %d\n", xpd_num);
@@ -480,6 +723,8 @@ int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
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));
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "%s: Bad xpd_num = %d\n", __FUNCTION__, xpd_num);
goto out;
@@ -498,6 +743,7 @@ int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
xbus->xpds[xpd_num] = NULL;
xbus->num_xpds--;
xpd->xbus = NULL;
+ put_xbus(xbus); /* we got it in xbus_register_xpd() */
ret = 0;
out:
spin_unlock_irqrestore(&xbus->lock, flags);
@@ -547,24 +793,27 @@ static void xbus_poll(void *data)
xbus_t *xbus;
BUG_ON(!poller);
- xbus = poller->xbus;
- BUG_ON(!xbus);
- if(!down_read_trylock(&xbus->in_use)) {
- XBUS_ERR(xbus, "Is being removed...\n");
+ 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(GENERAL, xbus, "\n");
+ XBUS_DBG(DEVICES, xbus, "\n");
poller->is_polling = 1;
-
+ if(!XBUS_GET(xbus)) {
+ XBUS_ERR(xbus, "Aborting poll. Is shutting down.\n");
+ goto out;
+ }
/*
* Send out the polls
*/
for(id = 0; id < MAX_XPDS; id++) {
- if(!xbus->hardware_exists)
+ if(!TRANSPORT_RUNNING(xbus))
break;
- // XBUS_DBG(GENERAL, xbus, "Polling slot %d\n", id);
+ 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);
@@ -577,7 +826,7 @@ static void xbus_poll(void *data)
/*
* Wait for replies
*/
- XBUS_DBG(GENERAL, xbus, "Polled %d XPD's. Waiting for replies max %d jiffies\n", MAX_XPDS, poll_timeout);
+ 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");
@@ -588,7 +837,7 @@ static void xbus_poll(void *data)
XBUS_ERR(xbus, "Poll interrupted %d\n", ret);
goto out;
} else
- XBUS_DBG(GENERAL, xbus, "Poll finished in %d jiffies.\n", poll_timeout - ret);
+ XBUS_DBG(DEVICES, xbus, "Poll finished in %d jiffies.\n", poll_timeout - ret);
/*
* Build removals/additions lists
*/
@@ -603,6 +852,12 @@ static void xbus_poll(void *data)
xpd_t *xpd;
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 */
@@ -666,10 +921,18 @@ static void xbus_poll(void *data)
XBUS_ERR(xbus, "%s: xbus_sysfs_create() failed: %d\n", __FUNCTION__, ret);
goto out;
}
- wake_up(&poller->wait_for_xpd_initialization);
+ /*
+ * 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 */
out:
poller->is_polling = 0; /* just for safety */
- up_read(&xbus->in_use);
+ XBUS_PUT(xbus);
+ wake_up(&poller->wait_for_xpd_initialization);
+ put_xbus(xbus);
return;
}
@@ -697,6 +960,12 @@ void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc)
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).
@@ -707,18 +976,30 @@ void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc)
static void poller_destroy(struct xbus_poller *poller)
{
+ xbus_t *xbus;
+
if(!poller)
return;
- if(poller->xbus) {
- XBUS_DBG(GENERAL, poller->xbus, "detach poller\n");
- poller->xbus->poller = NULL;
+ xbus = get_xbus(poller->xbus_num);
+ if(xbus) {
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir && poller->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;
+ }
+#endif
+ XBUS_DBG(DEVICES, xbus, "detach poller\n");
+ xbus->poller = NULL;
}
if (poller->wq) {
- XBUS_DBG(GENERAL, poller->xbus, "destroy workqueue\n");
+ DBG(DEVICES, "XBUS #%d: destroy workqueue\n", poller->xbus_num);
flush_workqueue(poller->wq);
destroy_workqueue(poller->wq);
poller->wq = NULL;
}
+ put_xbus(xbus);
+ memset(poller, 0, sizeof(*poller));
kfree(poller);
}
@@ -733,12 +1014,12 @@ static struct xbus_poller *poller_new(xbus_t *xbus)
BUG_ON(xbus->busname[0] == '\0'); /* No name? */
BUG_ON(xbus->poller); /* Hmmm... overrun pollers? */
- XBUS_DBG(GENERAL, xbus, "\n");
+ XBUS_DBG(DEVICES, xbus, "\n");
poller = kmalloc(sizeof(*poller), GFP_KERNEL);
if(!poller)
goto err;
memset(poller, 0, sizeof(*poller));
- poller->xbus = xbus;
+ poller->xbus_num = xbus->num;
xbus->poller = poller;
/* poll related variables */
atomic_set(&poller->count_poll_answers, 0);
@@ -752,6 +1033,20 @@ static struct xbus_poller *poller_new(xbus_t *xbus)
XBUS_ERR(xbus, "Failed to create poller workqueue.\n");
goto err;
}
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir) {
+ poller->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) {
+ XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_WAITFOR_XPDS);
+ goto err;
+ }
+ poller->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+ }
+#endif
return poller;
err:
poller_destroy(poller);
@@ -783,23 +1078,35 @@ static int poller_dispatch(xbus_t *xbus)
return 1;
}
-void xbus_activate(xbus_t *xbus)
+int xbus_activate(xbus_t *xbus)
{
- xbus_ops_t *ops;
+ struct xbus_ops *ops;
struct xbus_poller *poller;
BUG_ON(!xbus);
- ops = xbus->ops;
+ ops = transportops_get(xbus);
BUG_ON(!ops);
poller = xbus->poller;
BUG_ON(!poller);
/* Sanity checks */
- BUG_ON(!ops->xframe_send);
- BUG_ON(!ops->xframe_new || !ops->xframe_free);
- xbus->hardware_exists = 1;
- XBUS_DBG(GENERAL, xbus, "Activating\n");
+ BUG_ON(!ops->xframe_send_pcm);
+ BUG_ON(!ops->xframe_send_cmd);
+ BUG_ON(!ops->alloc_xframe);
+ BUG_ON(!ops->free_xframe);
+ xpp_timing_init(&xbus->timing, xbus->busname);
+ /*
+ * 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);
/* Poll it */
poller_dispatch(xbus);
+ return 0;
}
void xbus_disconnect(xbus_t *xbus)
@@ -807,8 +1114,9 @@ void xbus_disconnect(xbus_t *xbus)
int i;
BUG_ON(!xbus);
- XBUS_DBG(GENERAL, xbus, "\n");
- xbus->hardware_exists = 0;
+ XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
+ xbus_set_command_timer(xbus, 1);
+ xbus_request_sync(xbus, SYNC_MODE_PLL); /* no more ticks */
for(i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
if(!xpd)
@@ -819,8 +1127,22 @@ void xbus_disconnect(xbus_t *xbus)
}
xpd_disconnect(xpd);
}
- XBUS_DBG(GENERAL, xbus, "Deactivated\n");
- if(xbus->open_counter == 0) {
+ XBUS_DBG(DEVICES, xbus, "Deactivating\n");
+ tasklet_kill(&xbus->receive_tasklet);
+ xframe_queue_clear(&xbus->receive_queue);
+ xbus_command_queue_clean(xbus);
+ xbus_command_queue_waitempty(xbus);
+ del_timer_sync(&xbus->command_timer);
+ xframe_queue_clear(&xbus->send_pool);
+ xframe_queue_clear(&xbus->receive_pool);
+ xframe_queue_clear(&xbus->pcm_tospan[0]);
+ xframe_queue_clear(&xbus->pcm_tospan[1]);
+ 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);
}
}
@@ -839,7 +1161,7 @@ static xbus_t *xbus_alloc(void)
memset(xbus, 0, sizeof(xbus_t));
spin_lock_irqsave(&xbuses_lock, flags);
for(i = 0; i < MAX_BUSES; i++)
- if(xbuses_array[i] == NULL)
+ if(xbuses_array[i].xbus == NULL)
break;
if(i >= MAX_BUSES) {
ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
@@ -847,8 +1169,9 @@ static xbus_t *xbus_alloc(void)
return NULL;
}
/* Found empty slot */
- xbuses_array[i] = xbus;
xbus->num = i;
+ init_xbus(i, xbus);
+ xbus = get_xbus(i);
bus_count++;
spin_unlock_irqrestore(&xbuses_lock, flags);
return xbus;
@@ -858,14 +1181,14 @@ static xbus_t *xbus_alloc(void)
static void xbus_free(xbus_t *xbus)
{
unsigned long flags;
+ uint num;
if(!xbus)
return;
spin_lock_irqsave(&xbuses_lock, flags);
- BUG_ON(!xbus_of(xbus->num));
- BUG_ON(xbus != xbus_of(xbus->num));
- xbuses_array[xbus->num] = NULL;
- bus_count--;
+ num = xbus->num;
+ BUG_ON(!xbuses_array[num].xbus);
+ BUG_ON(xbus != xbuses_array[num].xbus);
spin_unlock_irqrestore(&xbuses_lock, flags);
#ifdef XPP_DEBUGFS
if(xbus->debugfs_dir) {
@@ -877,6 +1200,7 @@ 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) {
@@ -884,11 +1208,6 @@ static void xbus_free(xbus_t *xbus)
remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
xbus->proc_xbus_summary = NULL;
}
- if(xbus->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);
- xbus->proc_xbus_waitfor_xpds = NULL;
- }
#ifdef PROTOCOL_DEBUG
if(xbus->proc_xbus_command) {
XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_COMMAND);
@@ -901,42 +1220,48 @@ static void xbus_free(xbus_t *xbus)
xbus->proc_xbus_dir = NULL;
}
#endif
- poller_destroy(xbus->poller);
+ 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);
+ init_xbus(num, NULL);
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ memset(xbus, 0, sizeof(*xbus));
kfree(xbus);
}
-xbus_t *xbus_new(xbus_ops_t *ops, size_t xframe_size)
+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");
xbus = xbus_alloc();
if(!xbus)
return NULL;
- /* Init data structures */
- xbus->max_xframe_size = xframe_size;
+ 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_INFO(xbus, "New xbus\n");
- init_waitqueue_head(&xbus->packet_cache_empty);
- atomic_set(&xbus->packet_counter, 0);
- atomic_set(&xbus->pcm_nesting, 1);
+ init_waitqueue_head(&xbus->command_queue_empty);
+ init_timer(&xbus->command_timer);
+ atomic_set(&xbus->pcm_rx_counter, 0);
xbus->min_tx_sync = INT_MAX;
xbus->min_rx_sync = INT_MAX;
xbus->num_xpds = 0;
- /*
- * Create poller before /proc/XBUS-?? so it already exists
- * when somebody tries to read /proc/XBUS-??/waitfor_xpds
- */
- poller = poller_new(xbus);
- if(!poller) {
- ERR("Failed to allocate poller\n");
- xbus_free(xbus);
- return NULL;
- }
+ xbus->sync_mode = SYNC_MODE_NONE;
init_rwsem(&xbus->in_use);
xbus_reset_counters(xbus);
#ifdef CONFIG_PROC_FS
@@ -948,21 +1273,13 @@ xbus_t *xbus_new(xbus_ops_t *ops, size_t xframe_size)
goto nobus;
}
xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
- xbus_read_proc, xbus);
+ xbus_read_proc, (void *)(xbus->num));
if (!xbus->proc_xbus_summary) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_SUMMARY);
err = -EIO;
goto nobus;
}
xbus->proc_xbus_summary->owner = THIS_MODULE;
- xbus->proc_xbus_waitfor_xpds = create_proc_read_entry(PROC_XBUS_WAITFOR_XPDS, 0444, xbus->proc_xbus_dir,
- xbus_read_waitfor_xpds, xbus);
- if (!xbus->proc_xbus_waitfor_xpds) {
- XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_WAITFOR_XPDS);
- err = -EIO;
- goto nobus;
- }
- xbus->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
#ifdef PROTOCOL_DEBUG
xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
if (!xbus->proc_xbus_command) {
@@ -987,18 +1304,23 @@ xbus_t *xbus_new(xbus_ops_t *ops, size_t xframe_size)
goto nobus;
}
#endif
- /* Sanity checks */
- if(!ops->xframe_send) {
- XBUS_ERR(xbus, "missing mandatory handler: xframe_send\n");
- goto nobus;
- }
- if(!ops->xframe_new || !ops->xframe_free) {
- XBUS_NOTICE(xbus, "Using default packet allocators\n");
- ops->xframe_new = xbus_xframe_new;
- ops->xframe_free = xbus_xframe_free;
+ xframe_queue_init(&xbus->command_queue, 10, 200, "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[0], 5, 10, "pcm_tospan[0]", xbus);
+ xframe_queue_init(&xbus->pcm_tospan[1], 5, 10, "pcm_tospan[1]", xbus);
+ tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus);
+ /*
+ * Create poller 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->ops = ops;
return xbus;
nobus:
xbus_free(xbus);
@@ -1008,19 +1330,11 @@ nobus:
void xbus_remove(xbus_t *xbus)
{
int i;
- int ret;
-
- BUG_ON(!xbus);
- if(!xbus_of(xbus->num)) {
- DBG(GENERAL, "XBUS #%d was already removed. Skip.\n", xbus->num);
- return;
- }
- XBUS_DBG(GENERAL, xbus, "\n");
- /* Block until no one use */
+ BUG_ON(TRANSPORT_RUNNING(xbus));
down_write(&xbus->in_use);
- XBUS_INFO(xbus, "Removing xbus\n");
+ 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);
@@ -1030,16 +1344,11 @@ void xbus_remove(xbus_t *xbus)
XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
continue;
}
- XBUS_DBG(GENERAL, xbus, " Removing xpd #%d\n", i);
+ XBUS_DBG(DEVICES, xbus, " Removing xpd #%d\n", i);
xpd_remove(xpd);
}
xbus->xpds[i] = NULL;
}
- ret = wait_event_interruptible(xbus->packet_cache_empty,
- atomic_read(&xbus->packet_counter) == 0);
- if(ret) {
- XBUS_ERR(xbus, "waiting for packet_cache_empty interrupted!!!\n");
- }
xbus_free(xbus);
}
@@ -1056,43 +1365,95 @@ void xbus_reset_counters(xbus_t *xbus)
}
#if CONFIG_PROC_FS
+
+static int xbus_fill_proc_queue(char *p, struct xframe_queue *q)
+{
+ int len;
+
+ len = sprintf(p,
+ "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
+ q->name,
+ q->steady_state_count,
+ q->count,
+ q->max_count,
+ q->worst_count,
+ q->overflows,
+ q->worst_lag_usec / 1000,
+ q->worst_lag_usec % 1000);
+ xframe_queue_clearstats(q);
+ return len;
+}
+
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- xbus_t *xbus = data;
+ xbus_t *xbus;
struct xbus_poller *poller;
unsigned long flags;
int len = 0;
- int i;
+ int i = (int)data;
+ struct timeval now;
+
+ xbus = get_xbus(i);
if(!xbus)
goto out;
spin_lock_irqsave(&xbus->lock, flags);
+ do_gettimeofday(&now);
poller = xbus->poller;
- len += sprintf(page + len, "%s: CONNECTOR=%s SERIAL=[%s] STATUS=%s bus_type=%d\n",
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
xbus->busdesc,
- xbus->serialnum,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
+ 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, "\nmax_xframe_size=%d open_counter=%d packet_count=%d\n",
- xbus->max_xframe_size,
- xbus->open_counter,
- atomic_read(&xbus->packet_counter)
- );
- len += sprintf(page + len, "\nPLL DRIFT=%d\n", xbus->sync_adjustment);
+ 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);
+ len += xbus_fill_proc_queue(page + len, &xbus->receive_queue);
+ len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan[0]);
+ len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan[1]);
+ if(rx_tasklet) {
+ len += sprintf(page + len, "\ncpu_rcv_intr: ");
+ for_each_online_cpu(i)
+ len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]);
+ len += sprintf(page + len, "\ncpu_rcv_tasklet: ");
+ for_each_online_cpu(i)
+ len += sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]);
+ len += sprintf(page + len, "\n");
+ }
+ len += sprintf(page + len, "self_ticking: %d\n", xbus->self_ticking);
+ 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",
+ xbus->max_rx_process / 1000,
+ xbus->max_rx_process % 1000);
+ xbus->max_rx_process = 0;
+ len += sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n",
+ MAX_SEND_SIZE(xbus),
+ atomic_read(&xbus->transport.transport_refcount)
+ );
+ len += sprintf(page + len, "\nSYNC: [%d] %-14s: DRIFT=%d %3ld sec ago\n",
+ xbus->sync_mode, sync_mode_name(xbus->sync_mode), xbus->sync_adjustment,
+ (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at);
+ len += sprintf(page + len,
+ "tick timing: avg = %3d usec stddev = %4d usec (count=%ld)\n",
+ xbus->timing.tick_avg, xbus->timing.tick_stddev, xbus->timing.timing_count);
+ len += sprintf(page + len,
+ "sync_offset_usec=%ld\n", xbus->sync_offset_usec);
len += sprintf(page + len, "PCM Metrices:\n");
len += sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n",
xbus->min_tx_sync, xbus->max_tx_sync);
len += sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n",
xbus->min_rx_sync, xbus->max_rx_sync);
- len += sprintf(page + len, "max_rx_process=%ld\n", xbus->max_rx_process);
len += sprintf(page + len, "COUNTERS:\n");
for(i = 0; i < XBUS_COUNTER_MAX; i++) {
len += sprintf(page + len, "\t%-15s = %d\n",
@@ -1104,8 +1465,8 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
xbus->max_tx_sync = 0;
xbus->min_rx_sync = INT_MAX;
xbus->max_rx_sync = 0;
- xbus->max_rx_process = 0;
spin_unlock_irqrestore(&xbus->lock, flags);
+ put_xbus(xbus);
out:
if (len <= off+count)
*eof = 1;
@@ -1138,7 +1499,7 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
*/
poller = xbus->poller;
BUG_ON(!poller);
- XBUS_DBG(GENERAL, xbus,
+ 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);
/*
@@ -1165,7 +1526,7 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
XBUS_ERR(xbus, "Card Initialization Interrupted %d\n", ret);
return ret;
} else
- XBUS_DBG(GENERAL, xbus,
+ XBUS_DBG(DEVICES, xbus,
"Finished initialization of %d XPD's in %d seconds.\n",
atomic_read(&poller->count_xpds_initialized),
(INITIALIZATION_TIMEOUT - ret)/HZ);
@@ -1191,21 +1552,35 @@ out:
#ifdef PROTOCOL_DEBUG
static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
- char buf[MAX_PROC_WRITE];
+ char *buf;
xbus_t *xbus = data;
- xpacket_t *pack;
char *p;
byte *pack_start;
byte *q;
xframe_t *xframe;
+ size_t len;
+ const size_t max_len = xbus->transport.max_send_size;
+ const size_t max_text = max_len * 3 + 10;
- if(count >= MAX_PROC_WRITE) {
- XBUS_ERR(xbus, "%s: line too long\n", __FUNCTION__);
+ if(count > max_text) {
+ XBUS_ERR(xbus, "%s: line too long (%ld > %d)\n", __FUNCTION__, count, max_len);
return -EFBIG;
}
- if(copy_from_user(buf, buffer, count))
- return -EINVAL;
+ /* 3 bytes per hex-digit and space */
+ buf = kmalloc(max_text, GFP_KERNEL);
+ if(!buf)
+ return -ENOMEM;
+ if(copy_from_user(buf, buffer, count)) {
+ count = -EINVAL;
+ goto out;
+ }
buf[count] = '\0';
+ XBUS_DBG(GENERAL, xbus, "count=%ld\n", count);
+ /*
+ * We replace the content of buf[] from
+ * ascii representation to packet content
+ * as the binary representation is shorter
+ */
q = pack_start = buf;
for(p = buf; *p;) {
int val;
@@ -1218,7 +1593,8 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if(!isxdigit(*p)) {
XBUS_ERR(xbus, "%s: bad hex value ASCII='0x%X' at position %ld\n",
__FUNCTION__, *p, (long)(p - buf));
- return -EINVAL;
+ count = -EINVAL;
+ goto out;
}
hexdigit[0] = *p++;
hexdigit[1] = '\0';
@@ -1228,21 +1604,26 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if(sscanf(hexdigit, "%2X", &val) != 1) {
XBUS_ERR(xbus, "%s: bad hex value '%s' at position %ld\n",
__FUNCTION__, hexdigit, (long)(p - buf));
- return -EINVAL;
+ count = -EINVAL;
+ goto out;
}
*q++ = val;
- // XBUS_DBG(GENERAL, xbus, "'%s' val=%d\n", hexdigit, val);
+ XBUS_DBG(GENERAL, xbus, "%3d> '%s' val=%d\n", q - pack_start, hexdigit, val);
}
- xframe = xbus->ops->xframe_new(xbus, GFP_KERNEL);
- if(!xframe)
- return -ENOMEM;
- pack = xframe_next_packet(xframe, q - pack_start);
- if(!pack) {
- xbus->ops->xframe_free(xbus, xframe);
- return -ENOMEM;
+ len = q - pack_start;
+ xframe = ALLOC_SEND_XFRAME(xbus);
+ if(!xframe) {
+ count = -ENOMEM;
+ goto out;
}
- memcpy(pack, pack_start, q - pack_start); /* FRAMES: checksum? */
+ if(len > max_len)
+ len = max_len;
+ atomic_set(&xframe->frame_len, len);
+ memcpy(xframe->packets, pack_start, len); /* FIXME: checksum? */
+ dump_xframe("COMMAND", xbus, xframe);
send_cmd_frame(xbus, xframe);
+out:
+ kfree(buf);
return count;
}
#endif
@@ -1256,16 +1637,17 @@ 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 = xbus_of(i);
+ xbus_t *xbus = get_xbus(i);
if(xbus) {
- len += sprintf(page + len, "%s: CONNECTOR=%s SERIAL=[%s] STATUS=%s bus_type=%d\n",
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s REFCOUNT=%d\n",
xbus->busname,
xbus->busdesc,
- xbus->serialnum,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
+ xbus->label,
+ (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing",
+ refcount_xbus(i) - 1
);
+ put_xbus(xbus);
}
}
#if 0
@@ -1283,37 +1665,69 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
return len;
}
+#endif
-static int read_proc_xmitter(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)
{
- int len = 0;
- len += sprintf(page + len, "command_count: %d\n",
- command_count);
- len += sprintf(page + len, "sum_latency: %ld\n",
- sum_latency);
- if(command_count)
- len += sprintf(page + len, "average latency: %ld\n",
- sum_latency/command_count);
-#if 0
- len += sprintf(page + len, "<-- len=%d\n", len);
-#endif
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
+ BUG_ON(!xbus);
+ BUG_ON(!ops);
+ BUG_ON(!ops->xframe_send_pcm);
+ BUG_ON(!ops->xframe_send_cmd);
+ BUG_ON(!ops->alloc_xframe);
+ BUG_ON(!ops->free_xframe);
+ xbus->transport.ops = ops;
+ xbus->transport.max_send_size = max_send_size;
+ xbus->transport.priv = priv;
+ spin_lock_init(&xbus->transport.lock);
+ atomic_set(&xbus->transport.transport_refcount, 0);
+ init_waitqueue_head(&xbus->transport.transport_unused);
+}
+
+void transport_destroy(xbus_t *xbus)
+{
+ int ret;
+ BUG_ON(!xbus);
+ xbus->transport.transport_running = 0;
+ XBUS_INFO(xbus, "Waiting... (transport_refcount=%d)\n",
+ atomic_read(&xbus->transport.transport_refcount));
+ ret = wait_event_interruptible(xbus->transport.transport_unused,
+ atomic_read(&xbus->transport.transport_refcount) == 0);
+ if(ret)
+ XBUS_ERR(xbus, "Waiting for transport_refcount interrupted!!!\n");
+ xbus->transport.ops = NULL;
+ xbus->transport.priv = NULL;
}
-#endif
+struct xbus_ops *transportops_get(xbus_t *xbus)
+{
+ struct xbus_ops *ops;
+
+ BUG_ON(!xbus);
+ atomic_inc(&xbus->transport.transport_refcount);
+ ops = xbus->transport.ops;
+ if(!ops) {
+ atomic_dec(&xbus->transport.transport_refcount);
+ return NULL;
+ }
+ return ops;
+}
+
+void transportops_put(xbus_t *xbus)
+{
+ struct xbus_ops *ops;
+
+ BUG_ON(!xbus);
+ ops = xbus->transport.ops;
+ BUG_ON(!ops);
+ if(atomic_dec_and_test(&xbus->transport.transport_refcount))
+ wake_up(&xbus->transport.transport_unused);
+}
/*------------------------- Initialization -------------------------*/
static void xbus_core_cleanup(void)
{
+ finalize_xbuses_array();
#ifdef XPP_DEBUGFS
if(debugfs_root) {
DBG(GENERAL, "Removing xpp from debugfs\n");
@@ -1327,47 +1741,19 @@ static void xbus_core_cleanup(void)
proc_xbuses = NULL;
}
#endif
-#ifdef CONFIG_PROC_FS
- if(proc_commands) {
- DBG(PROC, "Removing %s from proc\n", PROC_CMDS);
- remove_proc_entry(PROC_CMDS, xpp_proc_toplevel);
- proc_commands = NULL;
- }
-#endif
- if(xframes_cache)
- kmem_cache_destroy(xframes_cache);
}
int __init xbus_core_init(void)
{
int ret = 0;
+ initialize_xbuses_array();
#ifdef PROTOCOL_DEBUG
INFO("FEATURE: with PROTOCOL_DEBUG\n");
#endif
#ifdef XPP_DEBUGFS
INFO("FEATURE: with XPP_DEBUGFS support\n");
#endif
- xframes_cache = kmem_cache_create("xpp_frames",
- sizeof(xframe_t) + XFRAME_DATASIZE,
- 0, 0,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
- NULL,
-#endif
- NULL);
- if(!xframes_cache) {
- return -ENOMEM;
- }
-#ifdef CONFIG_PROC_FS
- proc_commands = create_proc_read_entry(
- PROC_CMDS, 0444, xpp_proc_toplevel,
- read_proc_xmitter, NULL);
- if (!proc_commands) {
- ERR("Failed to create proc file %s\n", PROC_CMDS);
- goto err;
- }
- proc_commands->owner = THIS_MODULE;
-#endif
#ifdef CONFIG_PROC_FS
proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, NULL);
if (!proc_xbuses) {
@@ -1400,9 +1786,11 @@ void __exit xbus_core_shutdown(void)
int i;
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = xbus_of(i);
- if(xbus)
+ xbus_t *xbus = get_xbus(i);
+
+ if(xbus) {
xbus_remove(xbus);
+ }
}
BUG_ON(bus_count);
unregister_xpp_bus();
@@ -1411,16 +1799,23 @@ void __exit xbus_core_shutdown(void)
EXPORT_SYMBOL(xpd_of);
EXPORT_SYMBOL(xpd_byaddr);
+EXPORT_SYMBOL(get_xbus);
+EXPORT_SYMBOL(put_xbus);
EXPORT_SYMBOL(xbus_new);
EXPORT_SYMBOL(xbus_remove);
EXPORT_SYMBOL(xbus_activate);
EXPORT_SYMBOL(xbus_disconnect);
+EXPORT_SYMBOL(xbus_receive_xframe);
EXPORT_SYMBOL(xbus_reset_counters);
EXPORT_SYMBOL(xframe_next_packet);
EXPORT_SYMBOL(dump_xframe);
-EXPORT_SYMBOL(xframe_send);
+EXPORT_SYMBOL(send_pcm_frame);
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);
#endif