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.c433
1 files changed, 353 insertions, 80 deletions
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
index 9f3b24b..2391d44 100644
--- a/xpp/xbus-core.c
+++ b/xpp/xbus-core.c
@@ -37,6 +37,9 @@
#include "xpd.h"
#include "xpp_zap.h"
#include "xbus-core.h"
+#ifdef XPP_DEBUGFS
+#include "xpp_log.h"
+#endif
#include "zap_debug.h"
static const char rcsid[] = "$Id$";
@@ -55,7 +58,7 @@ 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, POLL_TIMEOUT,"Timeout (in jiffies) waiting for units to reply (default " __stringify(POLL_TIMEOUT) ")");
+DEF_PARM(uint, poll_timeout, POLL_TIMEOUT, 0600, "Timeout (in jiffies) waiting for units to reply (default " __stringify(POLL_TIMEOUT) ")");
/* Forward declarations */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
@@ -83,53 +86,274 @@ 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);
-/*------------------------- Packet Handling ------------------------*/
-static kmem_cache_t *packet_cache = NULL;
-static atomic_t xpacket_count = ATOMIC_INIT(0);
-
-/**
- * Allocates a new XPP packet.
- * @xbus The XPP bus in which the packet will flow (for counters
- * maintenance)
- * @flags Flags for kernel memory allocation.
- * @returns A pointer to the new packet, or NULL in case of failure.
- *
- *
- * Packet allocation/deallocation:
- * Sent packets:
- * - Allocated by protocol commands
- * - Deallocated by xmus_xmitter
- * Receive packets:
- * - Allocated/deallocated by xbus_xmiter
+/*------------------------- Debugfs Handling -----------------------*/
+#ifdef XPP_DEBUGFS
+
+#define DEBUGFS_BUFSIZ 4096 /* must be power of two, otherwise POS_IN_BUF will have to use '%' instead of '&' */
+#define POS_IN_BUF(x) ((x) & (DEBUGFS_BUFSIZ-1))
+
+struct debugfs_data {
+ spinlock_t lock;
+ xbus_t *xbus;
+ char buffer[DEBUGFS_BUFSIZ];
+ unsigned long head, tail; /* reading and writing are performed at position (head % BUF_SIZ) and (tail % BUF_SIZ) */
+ wait_queue_head_t queue;
+};
+
+static unsigned long add_to_buf(struct debugfs_data *d, unsigned long tail, const void *buf, unsigned long len)
+{
+ unsigned long count = min(len, (unsigned long)(DEBUGFS_BUFSIZ - POS_IN_BUF(tail)));
+ memcpy(d->buffer + POS_IN_BUF(tail), buf, count); /* fill starting at position tail */
+ memcpy(d->buffer, (u_char *)buf + count, len - count); /* fill leftover */
+ return len;
+}
+
+int xbus_log(xbus_t *xbus, xpd_t *xpd, int direction, const void *buf, unsigned long len)
+{
+ unsigned long tail;
+ unsigned long flags;
+ struct debugfs_data *d;
+ struct log_header header;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ BUG_ON(sizeof(struct log_header) + len > DEBUGFS_BUFSIZ);
+ d = xbus->debugfs_data;
+ if (!d) /* no consumer process */
+ return ret;
+ spin_lock_irqsave(&d->lock, flags);
+ if (sizeof(struct log_header) + len > DEBUGFS_BUFSIZ - (d->tail - d->head)) {
+ ret = -ENOSPC;
+ DBG("Dropping debugfs data of len %lu, free space is %lu\n", sizeof(struct log_header) + len,
+ DEBUGFS_BUFSIZ - (d->tail - d->head));
+ goto out;
+ }
+ header.len = sizeof(struct log_header) + len;
+ header.time = jiffies_to_msecs(jiffies);
+ header.xpd_num = xpd->id;
+ header.direction = (char)direction;
+ tail = d->tail;
+ tail += add_to_buf(d, tail, &header, sizeof(header));
+ tail += add_to_buf(d, tail, buf, len);
+ d->tail = tail;
+ wake_up_interruptible(&d->queue);
+out:
+ spin_unlock_irqrestore(&d->lock, flags);
+ return ret;
+}
+
+static struct dentry *debugfs_root = NULL;
+static int debugfs_open(struct inode *inode, struct file *file);
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos);
+static int debugfs_release(struct inode *inode, struct file *file);
+
+struct file_operations debugfs_operations = {
+ .open = debugfs_open,
+ .read = debugfs_read,
+ .release = debugfs_release,
+};
+
+/*
+ * As part of the "inode diet" the private data member of struct inode
+ * has changed in 2.6.19. However, Fedore Core 6 adopted this change
+ * a bit earlier (2.6.18). If you use vanila kernel (or Debian Etch)
+ * Change the following test from 2,6,18 to 2,6,19.
*/
-xpacket_t *xbus_packet_new(xbus_t *xbus, gfp_t flags)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define I_PRIVATE(inode) ((inode)->u.generic_ip)
+#else
+#define I_PRIVATE(inode) ((inode)->i_private)
+#endif
+
+static int debugfs_open(struct inode *inode, struct file *file)
{
- xpacket_t *pack;
+ xbus_t *xbus = I_PRIVATE(inode);
+ struct debugfs_data *d;
+ struct log_global_header gheader;
+
+ BUG_ON(!xbus);
+ DBG("%s\n", xbus->busname);
+ if (xbus->debugfs_data)
+ return -EBUSY;
+ d = kmalloc(sizeof(struct debugfs_data), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+ try_module_get(THIS_MODULE);
+ memset(d, 0, sizeof(struct debugfs_data));
+ spin_lock_init(&d->lock);
+ d->xbus = xbus;
+ d->head = d->tail = 0;
+ init_waitqueue_head(&d->queue);
+ file->private_data = d;
+
+ gheader.magic = XPP_LOG_MAGIC;
+ gheader.version = 1;
+ d->tail += add_to_buf(d, d->tail, &gheader, sizeof(gheader));
+
+ xbus->debugfs_data = d;
+ return 0;
+}
- /* To avoid races we increament counter in advance and decrement it later
- * in case of failure */
- atomic_inc(&xbus->packet_counter);
- //DBG("Incremented packet_counter of bus %s (new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
- pack = kmem_cache_alloc(packet_cache, flags);
- if (pack) {
- memset(pack, 0, sizeof(xpacket_t));
- atomic_inc(&xpacket_count);
- } else {
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+{
+ struct debugfs_data *d = file->private_data;
+ size_t len;
+
+ BUG_ON(!d);
+ BUG_ON(!d->xbus);
+ DBG("%s\n", d->xbus->busname);
+ while (d->head == d->tail) {
+ if (wait_event_interruptible(d->queue, d->head != d->tail))
+ return -EAGAIN;
+ }
+ len = min(nbytes, (size_t)(d->tail - d->head));
+ if (copy_to_user(buf, d->buffer + POS_IN_BUF(d->head), len))
+ return -EFAULT;
+ d->head += len;
+ /* optimization to avoid future buffer wraparound */
+ if (d->head == d->tail) {
+ unsigned long flags;
+ spin_lock_irqsave(&d->lock, flags);
+ if (d->head == d->tail)
+ d->head = d->tail = 0;
+ spin_unlock_irqrestore(&d->lock, flags);
}
- return pack;
+ return len;
+}
+
+static int debugfs_release(struct inode *inode, struct file *file)
+{
+ struct debugfs_data *d = file->private_data;
+
+ BUG_ON(!d);
+ BUG_ON(!d->xbus);
+ DBG("%s\n", d->xbus->busname);
+ d->xbus->debugfs_data = NULL;
+ kfree(d);
+ module_put(THIS_MODULE);
+ return 0;
+}
+#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)
+{
+ xframe_t *frm;
+
+ frm = kmem_cache_alloc(xframes_cache, flags);
+ if(!frm)
+ return NULL;
+ memset(frm, 0, sizeof(xframe_t) + XFRAME_DATASIZE);
+ atomic_set(&frm->frame_len, 0);
+ frm->packets = (byte *)frm + sizeof(xframe_t);
+ return frm;
}
-void xbus_packet_free(xbus_t *xbus, xpacket_t *p)
+void xbus_xframe_free(xbus_t *xbus, xframe_t *p)
{
- kmem_cache_free(packet_cache, p);
- atomic_dec(&xpacket_count);
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
+ kmem_cache_free(xframes_cache, p);
+}
+
+/*
+ * Return pointer to next packet slot in the frame
+ * or NULL if the frame is full.
+ */
+xpacket_t *xframe_next_packet(xframe_t *frm, int len)
+{
+ int newlen = atomic_add_return(len, &frm->frame_len);
+// DBG("len=%d, newlen=%d, frm->frame_len=%d\n", len, newlen, XFRAME_LEN(frm));
+ if (newlen > XFRAME_DATASIZE) {
+ atomic_sub(len, &frm->frame_len);
+ return NULL;
+ }
+ return (xpacket_t *)(frm->packets + newlen - len);
+}
+
+static spinlock_t serialize_dump_xframe = SPIN_LOCK_UNLOCKED;
+
+static void do_hexdump(const char msg[], byte *data, uint16_t len)
+{
+ int i;
+
+ for(i = 0; i < len; i++)
+ DBG("%s: %3d> %02X\n", msg, i, data[i]);
+}
+
+void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe)
+{
+ const uint16_t frame_len = XFRAME_LEN(xframe);
+ xpacket_t *pack;
+ uint16_t pos = 0;
+ uint16_t nextpos;
+ int num = 1;
+ bool do_print;
+ static int rate_limit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serialize_dump_xframe, flags);
+ do {
+ if(pos >= XFRAME_DATASIZE) {
+ if(printk_ratelimit()) {
+ ERR("%s: xframe overflow (%d bytes)\n",
+ msg, frame_len);
+ do_hexdump(msg, xframe->packets, frame_len);
+ }
+ break;
+ }
+ if(pos > frame_len) {
+ if(printk_ratelimit()) {
+ ERR("%s: packet overflow pos=%d frame_len=%d\n",
+ msg, pos, frame_len);
+ do_hexdump(msg, xframe->packets, frame_len);
+ }
+ break;
+ }
+ 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",
+ msg, pack->datalen, pos, frame_len);
+ do_hexdump(msg, xframe->packets, frame_len);
+ }
+ break;
+ }
+ nextpos = pos + pack->datalen;
+ if(nextpos > frame_len) {
+ if(printk_ratelimit()) {
+ ERR("%s: packet overflow nextpos=%d frame_len=%d\n",
+ msg, nextpos, frame_len);
+ do_hexdump(msg, xframe->packets, frame_len);
+ }
+ break;
+ }
+ do_print = 0;
+ if(pack->opcode != XPROTO_NAME(GLOBAL,PCM_READ) &&
+ pack->opcode != XPROTO_NAME(GLOBAL,PCM_WRITE))
+ do_print = 1;
+ if((print_dbg & DBG_PCM) && ((rate_limit % 1003) == 0))
+ do_print = 1;
+ if(do_print) {
+ 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",
+ num, pack->datalen, pack->opcode,
+ pack->addr.unit, pack->addr.subunit, pos);
+ dump_packet(" ", pack, print_dbg);
+ }
+ num++;
+ pos = nextpos;
+ if(pos >= frame_len)
+ break;
+ } while(1);
+ spin_unlock_irqrestore(&serialize_dump_xframe, flags);
}
@@ -141,7 +365,7 @@ xbus_t *xbus_of(int xbus_num)
return xbuses_array[xbus_num];
}
-xpd_t *xpd_of(xbus_t *xbus, int xpd_num)
+xpd_t *xpd_of(const xbus_t *xbus, int xpd_num)
{
if(!VALID_XPD_NUM(xpd_num))
return NULL;
@@ -227,7 +451,6 @@ static void xbus_poll(void *data)
struct list_head additions_list;
int count_removed;
int count_added;
- int xpd_num;
if(!down_read_trylock(&xbus->in_use)) {
ERR("%s is being removed...\n", xbus->busname);
@@ -283,8 +506,7 @@ static void xbus_poll(void *data)
xpd_t *xpd;
BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
- xpd_num = xpd_addr2num(&card_desc->xpd_addr);
- xpd = xpd_of(xbus, xpd_num);
+ xpd = xpd_by_addr(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);
@@ -312,8 +534,7 @@ static void xbus_poll(void *data)
xpd_t *xpd;
list_del(card);
- xpd_num = xpd_addr2num(&card_desc->xpd_addr);
- xpd = xpd_of(xbus, xpd_num);
+ xpd = xpd_by_addr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit);
if(xpd)
xpd_disconnect(xpd);
kfree(card);
@@ -332,6 +553,7 @@ static void xbus_poll(void *data)
wake_up(&xbus->wait_for_xpd_initialization);
out:
up_read(&xbus->in_use);
+ return;
}
@@ -343,16 +565,18 @@ void xbus_activate(xbus_t *xbus)
ops = xbus->ops;
BUG_ON(!ops);
/* Sanity checks */
- BUG_ON(!ops->packet_send);
- BUG_ON(!ops->packet_new || !ops->packet_free);
+ BUG_ON(!ops->xframe_send);
+ BUG_ON(!ops->xframe_new || !ops->xframe_free);
xbus->hardware_exists = 1;
DBG("Activating: %s\n", xbus->busname);
+
/* Poll it */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
INIT_WORK(&xbus->xpds_init_work, xbus_poll);
#else
INIT_WORK(&xbus->xpds_init_work, xbus_poll, xbus);
#endif
+
if(!queue_work(xpp_worker, &xbus->xpds_init_work)) {
ERR("Failed to queue xpd initialization work\n");
/* FIXME: need to return error */
@@ -424,6 +648,16 @@ static void xbus_free(xbus_t *xbus)
xbuses_array[xbus->num] = NULL;
bus_count--;
spin_unlock_irqrestore(&xbuses_lock, flags);
+#ifdef XPP_DEBUGFS
+ if(xbus->debugfs_dir) {
+ if(xbus->debugfs_file) {
+ DBG("Removing debugfs file for %s\n", xbus->busname);
+ debugfs_remove(xbus->debugfs_file);
+ }
+ DBG("Removing debugfs directory for %s\n", xbus->busname);
+ debugfs_remove(xbus->debugfs_dir);
+ }
+#endif
#ifdef CONFIG_PROC_FS
if(xbus->proc_xbus_dir) {
if(xbus->proc_xbus_summary) {
@@ -476,7 +710,7 @@ xbus_t *xbus_new(xbus_ops_t *ops)
/* Init data structures */
spin_lock_init(&xbus->lock);
- snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus->num);
+ snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
INFO("New xbus: %s\n", xbus->busname);
init_waitqueue_head(&xbus->packet_cache_empty);
atomic_set(&xbus->packet_counter, 0);
@@ -550,15 +784,27 @@ xbus_t *xbus_new(xbus_ops_t *ops)
xbus->proc_xbus_command->owner = THIS_MODULE;
#endif
#endif
+#ifdef XPP_DEBUGFS
+ xbus->debugfs_dir = debugfs_create_dir(xbus->busname, debugfs_root);
+ if(!xbus->debugfs_dir) {
+ ERR("Failed to create debugfs directory for %s\n", xbus->busname);
+ goto nobus;
+ }
+ xbus->debugfs_file = debugfs_create_file("dchannel", S_IFREG|S_IRUGO|S_IWUSR, xbus->debugfs_dir, xbus, &debugfs_operations);
+ if(!xbus->debugfs_file) {
+ ERR("Failed to create dchannel file for %s\n", xbus->busname);
+ goto nobus;
+ }
+#endif
/* Sanity checks */
- if(!ops->packet_send) {
- ERR("%s: missing mandatory handler: packet_send\n", __FUNCTION__);
+ if(!ops->xframe_send) {
+ ERR("%s: missing mandatory handler: xframe_send\n", __FUNCTION__);
goto nobus;
}
- if(!ops->packet_new || !ops->packet_free) {
+ if(!ops->xframe_new || !ops->xframe_free) {
NOTICE("%s: Using default packet allocators\n", __FUNCTION__);
- ops->packet_new = xbus_packet_new;
- ops->packet_free = xbus_packet_free;
+ ops->xframe_new = xbus_xframe_new;
+ ops->xframe_free = xbus_xframe_free;
}
xbus->ops = ops;
@@ -694,7 +940,8 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
}
DBG("%s: Finished initialization of %d XPD's in %d seconds.\n", xbus->busname, MAX_XPDS, (INITIALIZATION_TIMEOUT - ret)/HZ);
spin_lock_irqsave(&xbus->lock, flags);
- len += sprintf(page + len, "XPDS_READY: %d/%d\n",
+ len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n",
+ xbus->busname,
atomic_read(&xbus->count_xpds_initialized),
atomic_read(&xbus->count_xpds_to_initialize));
spin_unlock_irqrestore(&xbus->lock, flags);
@@ -718,8 +965,9 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
xbus_t *xbus = data;
xpacket_t *pack;
char *p;
- byte *pack_contents;
+ byte *pack_start;
byte *q;
+ xframe_t *xframe;
if(count >= MAX_PROC_WRITE) {
ERR("%s: line too long\n", __FUNCTION__);
@@ -728,10 +976,7 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if(copy_from_user(buf, buffer, count))
return -EINVAL;
buf[count] = '\0';
- pack = xbus->ops->packet_new(xbus, GFP_KERNEL);
- if(!pack)
- return -ENOMEM;
- q = pack_contents = (byte *)&pack->content;
+ q = pack_start = buf;
for(p = buf; *p;) {
int val;
char hexdigit[3];
@@ -743,7 +988,7 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if(!isxdigit(*p)) {
ERR("%s: %s: bad hex value ASCII='0x%X' at position %d\n",
__FUNCTION__, xbus->busname, *p, p - buf);
- goto err;
+ return -EINVAL;
}
hexdigit[0] = *p++;
hexdigit[1] = '\0';
@@ -753,18 +998,22 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if(sscanf(hexdigit, "%2X", &val) != 1) {
ERR("%s: %s: bad hex value '%s' at position %d\n",
__FUNCTION__, xbus->busname, hexdigit, p - buf);
- goto err;
+ return -EINVAL;
}
*q++ = val;
// DBG("%s: %s: '%s' val=%d\n", __FUNCTION__, xbus->busname, hexdigit, val);
}
- pack->datalen = q - pack_contents -
- sizeof(pack->content.opcode) - sizeof(pack->content.addr);
- packet_send(xbus, pack);
+ 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;
+ }
+ memcpy(pack, pack_start, q - pack_start); /* FRAMES: checksum? */
+ xframe_send(xbus, xframe);
return count;
-err:
- xbus->ops->packet_free(xbus, pack);
- return -EINVAL;
}
#endif
@@ -861,6 +1110,12 @@ static void xbus_core_cleanup(void)
destroy_workqueue(xpp_worker);
xpp_worker = NULL;
}
+#ifdef XPP_DEBUGFS
+ if(debugfs_root) {
+ DBG("Removing xpp from debugfs\n");
+ debugfs_remove(debugfs_root);
+ }
+#endif
#ifdef CONFIG_PROC_FS
if(proc_xbuses) {
DBG("Removing " PROC_XBUSES " from proc\n");
@@ -868,8 +1123,8 @@ static void xbus_core_cleanup(void)
proc_xbuses = NULL;
}
#endif
- if(packet_cache)
- kmem_cache_destroy(packet_cache);
+ if(xframes_cache)
+ kmem_cache_destroy(xframes_cache);
}
int __init xbus_core_init(void)
@@ -879,35 +1134,48 @@ int __init xbus_core_init(void)
#ifdef PROTOCOL_DEBUG
INFO("FEATURE: %s with PROTOCOL_DEBUG\n", THIS_MODULE->name);
#endif
- packet_cache = kmem_cache_create("xpp_packets",
- sizeof(xpacket_t),
+#ifdef XPP_DEBUGFS
+ INFO("FEATURE: %s with XPP_DEBUGFS support\n", THIS_MODULE->name);
+#endif
+ xframes_cache = kmem_cache_create("xpp_frames",
+ sizeof(xframe_t) + XFRAME_DATASIZE,
0, 0,
NULL, NULL);
- if(!packet_cache) {
+ if(!xframes_cache) {
return -ENOMEM;
}
xpp_worker = create_singlethread_workqueue("xppworker");
if(!xpp_worker) {
ERR("Failed to create card detector workqueue.\n");
- xbus_core_cleanup();
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
#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);
- xbus_core_cleanup();
- return -EFAULT;
+ ret = -EFAULT;
+ goto err;
}
proc_xbuses->owner = THIS_MODULE;
#endif
+#ifdef XPP_DEBUGFS
+ DBG("Creating debugfs xpp root\n");
+ debugfs_root = debugfs_create_dir("xpp", NULL);
+ if(!debugfs_root) {
+ ret = -EFAULT;
+ goto err;
+ }
+#endif
ret = bus_register(&xbus_bus_type);
if(ret) {
ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
- xbus_core_cleanup();
- return ret;
+ goto err;
}
return 0;
+err:
+ xbus_core_cleanup();
+ return ret;
}
@@ -931,3 +1199,8 @@ EXPORT_SYMBOL(xbus_remove);
EXPORT_SYMBOL(xbus_activate);
EXPORT_SYMBOL(xbus_disconnect);
EXPORT_SYMBOL(xbus_reset_counters);
+EXPORT_SYMBOL(xframe_next_packet);
+EXPORT_SYMBOL(dump_xframe);
+#ifdef XPP_DEBUGFS
+EXPORT_SYMBOL(xbus_log);
+#endif