diff options
Diffstat (limited to 'xpp/xbus-core.c')
-rw-r--r-- | xpp/xbus-core.c | 180 |
1 files changed, 154 insertions, 26 deletions
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c index 3c057da..cbec226 100644 --- a/xpp/xbus-core.c +++ b/xpp/xbus-core.c @@ -76,6 +76,8 @@ static DEVICE_ATTR_FUNC(status_show, dev, buf); static void xbus_release(struct device *dev); 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); + /* Data structures */ static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED; @@ -86,6 +88,14 @@ static struct proc_dir_entry *proc_xbuses = NULL; static DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL); static DEVICE_ATTR(status, S_IRUGO, status_show, NULL); +/* + * Command Statistics + */ +uint command_count; +ulong sum_latency; +struct proc_dir_entry *proc_commands; +#define PROC_CMDS "cmds" + /*------------------------- Debugfs Handling -----------------------*/ #ifdef XPP_DEBUGFS @@ -131,7 +141,7 @@ int xbus_log(xbus_t *xbus, xpd_t *xpd, int direction, const void *buf, unsigned } header.len = sizeof(struct log_header) + len; header.time = jiffies_to_msecs(jiffies); - header.xpd_num = xpd->id; + header.xpd_num = xpd->xbus_idx; header.direction = (char)direction; tail = d->tail; tail += add_to_buf(d, tail, &header, sizeof(header)); @@ -252,6 +262,8 @@ xframe_t *xbus_xframe_new(xbus_t *xbus, gfp_t flags) return NULL; memset(frm, 0, sizeof(xframe_t) + XFRAME_DATASIZE); atomic_set(&frm->frame_len, 0); + frm->xbus = xbus; + do_gettimeofday(&frm->tv_created); frm->packets = (byte *)frm + sizeof(xframe_t); return frm; } @@ -288,6 +300,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; for(i = 0; i < len; i++) DBG("%s: %3d> %02X\n", msg, i, data[i]); @@ -308,7 +321,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) do { if(pos >= XFRAME_DATASIZE) { if(printk_ratelimit()) { - ERR("%s: xframe overflow (%d bytes)\n", + NOTICE("%s: xframe overflow (%d bytes)\n", msg, frame_len); do_hexdump(msg, xframe->packets, frame_len); } @@ -316,7 +329,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) } if(pos > frame_len) { if(printk_ratelimit()) { - ERR("%s: packet overflow pos=%d frame_len=%d\n", + NOTICE("%s: packet overflow pos=%d frame_len=%d\n", msg, pos, frame_len); do_hexdump(msg, xframe->packets, frame_len); } @@ -325,7 +338,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) pack = (xpacket_t *)&xframe->packets[pos]; if(pack->datalen <= 0) { if(printk_ratelimit()) { - ERR("%s: xframe -- bad datalen=%d pos=%d frame_len=%d\n", + NOTICE("%s: xframe -- bad datalen=%d pos=%d frame_len=%d\n", msg, pack->datalen, pos, frame_len); do_hexdump(msg, xframe->packets, frame_len); } @@ -334,7 +347,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) nextpos = pos + pack->datalen; if(nextpos > frame_len) { if(printk_ratelimit()) { - ERR("%s: packet overflow nextpos=%d frame_len=%d\n", + NOTICE("%s: packet overflow nextpos=%d frame_len=%d\n", msg, nextpos, frame_len); do_hexdump(msg, xframe->packets, frame_len); } @@ -350,7 +363,7 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) if(num == 1) DBG("%s: %s: frame_len=%d.\n", msg, xbus->busname, frame_len); - DBG(" %3d. DATALEN=%d OP=0x%02X XPD-%d-%d (pos=%d)\n", + DBG(" %3d. DATALEN=%d OP=0x%02X XPD-%d%d (pos=%d)\n", num, pack->datalen, pack->opcode, pack->addr.unit, pack->addr.subunit, pos); dump_packet(" ", pack, print_dbg); @@ -363,6 +376,59 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe) spin_unlock_irqrestore(&serialize_dump_xframe, flags); } +/** + * + * 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 ret = -ENODEV; + + if(!xframe) { + DBG("null xframe\n"); + return -EINVAL; + } + if(!xbus) { + DBG("null xbus\n"); + ret = -EINVAL; + goto error; + } + if (!xbus->hardware_exists) { + DBG("xbus %s Dropped a xframe -- NO HARDWARE.", xbus->busname); + ret = -ENODEV; + goto error; + } + if(down_read_trylock(&xbus->in_use)) { + ret = xbus->ops->xframe_send(xbus, xframe); + XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe); + up_read(&xbus->in_use); + } else { + DBG("Dropped xframe. %s is in_use\n", xbus->busname); + } + return ret; + +error: + xbus->ops->xframe_free(xbus, xframe); + return ret; +} + +int send_cmd_frame(xbus_t *xbus, xframe_t *xframe) +{ + struct timeval now; + struct timeval *created = &xframe->tv_created; + ulong usec_diff; + + DBG("%s:\n", xbus->busname); + 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); +} /*------------------------- Bus Management -------------------------*/ xbus_t *xbus_of(int xbus_num) @@ -379,9 +445,16 @@ xpd_t *xpd_of(const xbus_t *xbus, int xpd_num) return xbus->xpds[xpd_num]; } +xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit) +{ + if(unit > MAX_UNIT || subunit > MAX_SUBUNIT) + return NULL; + return xbus->xpds[XPD_IDX(unit,subunit)]; +} + int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd) { - unsigned int xpd_num = xpd->id; + unsigned int xpd_num = xpd->xbus_idx; unsigned long flags; int ret = 0; @@ -400,6 +473,7 @@ int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd) goto out; } xbus->xpds[xpd_num] = xpd; + xpd->xbus = xbus; xbus->num_xpds++; out: spin_unlock_irqrestore(&xbus->lock, flags); @@ -408,27 +482,31 @@ out: int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd) { - unsigned int xpd_num = xpd->id; + unsigned int xpd_num = xpd->xbus_idx; unsigned long flags; - int ret = 0; + int ret = -EINVAL; spin_lock_irqsave(&xbus->lock, flags); if(!VALID_XPD_NUM(xpd_num)) { - ERR("%s: Bad xpd_num = %d\n", xbus->busname, xpd_num); - ret = -EINVAL; + ERR("%s: %s: Bad xpd_num = %d\n", __FUNCTION__, xbus->busname, xpd_num); + goto out; + } + if(xbus->xpds[xpd_num] == NULL) { + ERR("%s: %s: slot xpd_num=%d is empty\n", + __FUNCTION__, xbus->busname, xpd_num); goto out; } if(xbus->xpds[xpd_num] != xpd) { xpd_t *other = xbus->xpds[xpd_num]; - ERR("%s: xpd_num=%d is occupied by %p (%s)\n", - xbus->busname, xpd_num, other, other->xpdname); - ret = -EINVAL; + ERR("%s: %s: slot xpd_num=%d is occupied by %p (%s)\n", + __FUNCTION__, xbus->busname, xpd_num, other, other->xpdname); goto out; } xbus->xpds[xpd_num] = NULL; xbus->num_xpds--; xpd->xbus = NULL; + ret = 0; out: spin_unlock_irqrestore(&xbus->lock, flags); return ret; @@ -485,7 +563,6 @@ static void xbus_poll(void *data) ERR("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id); goto out; } - mdelay(1); /* FIXME: debugging for Dima */ } spin_unlock_irqrestore(&xbus->lock, flags); /* @@ -517,7 +594,7 @@ static void xbus_poll(void *data) xpd_t *xpd; BUG_ON(card_desc->magic != CARD_DESC_MAGIC); - xpd = xpd_by_addr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); + xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); if(xpd && type == XPD_TYPE_NOMODULE) { /* card removal */ list_move_tail(card, &removal_list); @@ -545,7 +622,7 @@ static void xbus_poll(void *data) xpd_t *xpd; list_del(card); - xpd = xpd_by_addr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); + xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); if(xpd) xpd_disconnect(xpd); kfree(card); @@ -577,7 +654,7 @@ void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc) poller = xbus->poller; BUG_ON(!poller); if(!poller->is_polling) { - NOTICE("%s: %d-%d replied not during poll. Ignore\n", + NOTICE("%s: %d%d replied not during poll. Ignore\n", xbus->busname, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); @@ -710,8 +787,8 @@ void xbus_disconnect(xbus_t *xbus) xpd_t *xpd = xpd_of(xbus, i); if(!xpd) continue; - if(xpd->id != i) { - ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i); + if(xpd->xbus_idx != i) { + ERR("%s: BUG: xpd->xbus_idx=%d != i=%d\n", __FUNCTION__, xpd->xbus_idx, i); continue; } xpd_disconnect(xpd); @@ -830,6 +907,7 @@ xbus_t *xbus_new(xbus_ops_t *ops) INFO("New xbus: %s\n", xbus->busname); init_waitqueue_head(&xbus->packet_cache_empty); atomic_set(&xbus->packet_counter, 0); + atomic_set(&xbus->pcm_nesting, 1); xbus->min_tx_sync = INT_MAX; xbus->min_rx_sync = INT_MAX; @@ -840,7 +918,6 @@ xbus_t *xbus_new(xbus_ops_t *ops) xbus_free(xbus); return NULL; } - init_rwsem(&xbus->in_use); xbus_reset_counters(xbus); @@ -951,11 +1028,11 @@ void xbus_remove(xbus_t *xbus) xpd_t *xpd = xpd_of(xbus, i); if(xpd) { - if(xpd->id != i) { - ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i); + if(xpd->xbus_idx != i) { + ERR("%s: BUG: xpd->xbus_idx=%d != i=%d\n", __FUNCTION__, xpd->xbus_idx, i); continue; } - DBG(" Removing xpd id=%d\n", xpd->id); + DBG(" Removing xpd xbus_idx=%d\n", xpd->xbus_idx); xpd_remove(xpd); } xbus->xpds[i] = NULL; @@ -1022,6 +1099,11 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e xbus_counters[i].name, xbus->counters[i]); } len += sprintf(page + len, "<-- len=%d\n", len); + /* reset statistics */ + xbus->min_tx_sync = INT_MAX; + xbus->max_tx_sync = 0; + xbus->min_rx_sync = INT_MAX; + xbus->max_rx_sync = 0; spin_unlock_irqrestore(&xbus->lock, flags); out: if (len <= off+count) @@ -1139,7 +1221,7 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer, return -ENOMEM; } memcpy(pack, pack_start, q - pack_start); /* FRAMES: checksum? */ - xframe_send(xbus, xframe); + send_cmd_frame(xbus, xframe); return count; } #endif @@ -1179,6 +1261,32 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int return len; } + +static int read_proc_xmitter(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + 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; + +} + #endif /*------------------------- Initialization -------------------------*/ @@ -1245,13 +1353,20 @@ static void xbus_core_cleanup(void) proc_xbuses = NULL; } #endif +#ifdef CONFIG_PROC_FS + if(proc_commands) { + DBG("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; + int ret = 0; #ifdef PROTOCOL_DEBUG INFO("FEATURE: %s with PROTOCOL_DEBUG\n", THIS_MODULE->name); @@ -1267,6 +1382,16 @@ int __init xbus_core_init(void) 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) { ERR("Failed to create proc file %s\n", PROC_XBUSES); @@ -1311,6 +1436,7 @@ void __exit xbus_core_shutdown(void) } EXPORT_SYMBOL(xpd_of); +EXPORT_SYMBOL(xpd_byaddr); EXPORT_SYMBOL(xbus_new); EXPORT_SYMBOL(xbus_remove); EXPORT_SYMBOL(xbus_activate); @@ -1318,6 +1444,8 @@ EXPORT_SYMBOL(xbus_disconnect); EXPORT_SYMBOL(xbus_reset_counters); EXPORT_SYMBOL(xframe_next_packet); EXPORT_SYMBOL(dump_xframe); +EXPORT_SYMBOL(xframe_send); +EXPORT_SYMBOL(send_cmd_frame); EXPORT_SYMBOL(xbus_poller_notify); #ifdef XPP_DEBUGFS EXPORT_SYMBOL(xbus_log); |