From cfd61537b47387b0fb5c8228baad6cec16d8f6e6 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Tue, 18 Dec 2007 14:31:07 +0000 Subject: xpp r5151: * xpd_pri: Basically ready. * PCM synchronization changes: - Each Astribank unit ticks independently. Each with its own PLL. - HOST synchronization is gone. Loading of xpp will no longer cause useless 250 ticks per second if you have no Astribank. - Synchronization from the zaptel sync master requires setting ZAPTEL as sync source (xpp_sync ZAPTEL). * rx_tasklet is now a parameter of the module xpp, rather than of xpp_usb. * New FPGA firmware: 5128 (1151) / 5122 (1141, 1131): - Fixes synchronization issues. - PRI module: E1 should now work. * perl module and utilities: - Modules no longer magically scan system on initialization. - Scanning is by calling explicit methods. - "Serial" has been renamed "Label". It is basically unique, but should be modifieble. - Some basic documentation of zaptel perl modules. * Default sort order of zt_registration is back to SORT_CONNCTOR. * zt_registration proc file now shows the number of span registered to if registered. Try: grep . /proc/xpp/XBUS-*/XPD-*/zt_registration * genzaptelconf: Allow using a custom command instead of /etc/init.d/asterisk to start/stop asterisk. * Fixed the typo "Slagish". git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@3506 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/xbus-core.c | 931 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 663 insertions(+), 268 deletions(-) (limited to 'xpp/xbus-core.c') 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; } @@ -696,6 +959,12 @@ void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc) 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 @@ -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,46 +1741,18 @@ 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); @@ -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 -- cgit v1.2.3