[MIPS] Sibyte: Fix ZBbus profiler
authorRalf Baechle <ralf@linux-mips.org>
Fri, 9 Mar 2007 15:59:56 +0000 (15:59 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 9 Mar 2007 20:27:31 +0000 (20:27 +0000)
 o Fix build error.
 o Handle error returns.
 o Deal with signals received while sleeping.
 o Don't allow to be selected when we're not building the directory with
   the driver anyway.
 o Coding style cleanups.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/sibyte/Kconfig
arch/mips/sibyte/sb1250/bcm1250_tbprof.c
arch/mips/sibyte/sb1250/setup.c
include/asm-mips/sibyte/trace_prof.h [deleted file]

index 10cc403..bdf24a7 100644 (file)
@@ -8,12 +8,14 @@ config SIBYTE_SB1250
 config SIBYTE_BCM1120
        bool
        select SIBYTE_BCM112X
+       select SIBYTE_HAS_ZBUS_PROFILING
        select SIBYTE_SB1xxx_SOC
 
 config SIBYTE_BCM1125
        bool
        select HW_HAS_PCI
        select SIBYTE_BCM112X
+       select SIBYTE_HAS_ZBUS_PROFILING
        select SIBYTE_SB1xxx_SOC
 
 config SIBYTE_BCM1125H
@@ -21,11 +23,13 @@ config SIBYTE_BCM1125H
        select HW_HAS_PCI
        select SIBYTE_BCM112X
        select SIBYTE_ENABLE_LDT_IF_PCI
+       select SIBYTE_HAS_ZBUS_PROFILING
        select SIBYTE_SB1xxx_SOC
 
 config SIBYTE_BCM112X
        bool
        select SIBYTE_SB1xxx_SOC
+       select SIBYTE_HAS_ZBUS_PROFILING
 
 config SIBYTE_BCM1x80
        bool
@@ -37,6 +41,7 @@ config SIBYTE_BCM1x55
        bool
        select HW_HAS_PCI
        select SIBYTE_SB1xxx_SOC
+       select SIBYTE_HAS_ZBUS_PROFILING
        select SYS_SUPPORTS_SMP
 
 config SIBYTE_SB1xxx_SOC
@@ -164,5 +169,8 @@ config SIBYTE_SB1250_PROF
        depends on SIBYTE_SB1xxx_SOC
 
 config SIBYTE_TBPROF
-       bool "Support for ZBbus profiling"
-       depends on SIBYTE_SB1xxx_SOC
+       tristate "Support for ZBbus profiling"
+       depends on SIBYTE_HAS_ZBUS_PROFILING
+
+config SIBYTE_HAS_ZBUS_PROFILING
+       bool
index 212547c..ea0ca13 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
+ * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ *    written by Ralf Baechle <ralf@linux-mips.org>
  */
 
-#define SBPROF_TB_DEBUG 0
+#undef DEBUG
 
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/smp_lock.h>
+#include <linux/types.h>
 #include <linux/wait.h>
-#include <asm/uaccess.h>
+
 #include <asm/io.h>
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_scd.h>
 #include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/trace_prof.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
 
-#define DEVNAME "bcm1250_tbprof"
+#define SBPROF_TB_MAJOR 240
+
+typedef u64 tb_sample_t[6*256];
+
+enum open_status {
+       SB_CLOSED,
+       SB_OPENING,
+       SB_OPEN
+};
+
+struct sbprof_tb {
+       wait_queue_head_t       tb_sync;
+       wait_queue_head_t       tb_read;
+       struct mutex            lock;
+       enum open_status        open;
+       tb_sample_t             *sbprof_tbbuf;
+       int                     next_tb_sample;
+
+       volatile int            tb_enable;
+       volatile int            tb_armed;
+
+};
 
 static struct sbprof_tb sbp;
 
+#define MAX_SAMPLE_BYTES (24*1024*1024)
+#define MAX_TBSAMPLE_BYTES (12*1024*1024)
+
+#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
+#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
+#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
+
+/* ioctls */
+#define SBPROF_ZBSTART         _IOW('s', 0, int)
+#define SBPROF_ZBSTOP          _IOW('s', 1, int)
+#define SBPROF_ZBWAITFULL      _IOW('s', 2, int)
+
+/*
+ * Routines for using 40-bit SCD cycle counter
+ *
+ * Client responsible for either handling interrupts or making sure
+ * the cycles counter never saturates, e.g., by doing
+ * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
+ */
+
+/*
+ * Configures SCD counter 0 to count ZCLKs starting from val;
+ * Configures SCD counters1,2,3 to count nothing.
+ * Must not be called while gathering ZBbus profiles.
+ */
+
+#define zclk_timer_init(val) \
+  __asm__ __volatile__ (".set push;" \
+                       ".set mips64;" \
+                       "la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+                       "sd   %0, 0x10($8);"   /* write val to counter0 */ \
+                       "sd   %1, 0($8);"      /* config counter0 for zclks*/ \
+                       ".set pop" \
+                       : /* no outputs */ \
+                                                    /* enable, counter0 */ \
+                       : /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
+                       : /* modifies */ "$8" )
+
+
+/* Reads SCD counter 0 and puts result in value
+   unsigned long long val; */
+#define zclk_get(val) \
+  __asm__ __volatile__ (".set push;" \
+                       ".set mips64;" \
+                       "la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+                       "ld   %0, 0x10($8);"   /* write val to counter0 */ \
+                       ".set pop" \
+                       : /* outputs */ "=r"(val) \
+                       : /* inputs */ \
+                       : /* modifies */ "$8" )
+
+#define DEVNAME "bcm1250_tbprof"
+
 #define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES)
 
-/************************************************************************
+/*
  * Support for ZBbus sampling using the trace buffer
  *
  * We use the SCD performance counter interrupt, caused by a Zclk counter
@@ -54,30 +132,36 @@ static struct sbprof_tb sbp;
  * overflow.
  *
  * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
- *
- ************************************************************************/
+ */
 
-static u_int64_t tb_period;
+static u64 tb_period;
 
 static void arm_tb(void)
 {
-        u_int64_t scdperfcnt;
-       u_int64_t next = (1ULL << 40) - tb_period;
-       u_int64_t tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
-       /* Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
-          trigger start of trace.  XXX vary sampling period */
+        u64 scdperfcnt;
+       u64 next = (1ULL << 40) - tb_period;
+       u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
+
+       /*
+        * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to trigger
+        *start of trace.  XXX vary sampling period
+        */
        __raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
        scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
-       /* Unfortunately, in Pass 2 we must clear all counters to knock down
-          a previous interrupt request.  This means that bus profiling
-          requires ALL of the SCD perf counters. */
+
+       /*
+        * Unfortunately, in Pass 2 we must clear all counters to knock down a
+        * previous interrupt request.  This means that bus profiling requires
+        * ALL of the SCD perf counters.
+        */
        __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
-                                               // keep counters 0,2,3 as is
-                    M_SPC_CFG_ENABLE |         // enable counting
-                    M_SPC_CFG_CLEAR |          // clear all counters
-                    V_SPC_CFG_SRC1(1),         // counter 1 counts cycles
+                                               /* keep counters 0,2,3 as is */
+                    M_SPC_CFG_ENABLE |         /* enable counting */
+                    M_SPC_CFG_CLEAR |          /* clear all counters */
+                    V_SPC_CFG_SRC1(1),         /* counter 1 counts cycles */
                     IOADDR(A_SCD_PERF_CNT_CFG));
        __raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
+
        /* Reset the trace buffer */
        __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
 #if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
@@ -91,43 +175,45 @@ static void arm_tb(void)
 static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
 {
        int i;
-       DBG(printk(DEVNAME ": tb_intr\n"));
+
+       pr_debug(DEVNAME ": tb_intr\n");
+
        if (sbp.next_tb_sample < MAX_TB_SAMPLES) {
                /* XXX should use XKPHYS to make writes bypass L2 */
-               u_int64_t *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
+               u64 *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
                /* Read out trace */
                __raw_writeq(M_SCD_TRACE_CFG_START_READ,
                             IOADDR(A_SCD_TRACE_CFG));
                __asm__ __volatile__ ("sync" : : : "memory");
                /* Loop runs backwards because bundles are read out in reverse order */
                for (i = 256 * 6; i > 0; i -= 6) {
-                       // Subscripts decrease to put bundle in the order
-                       //   t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi
+                       /* Subscripts decrease to put bundle in the order */
+                       /*   t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */
                        p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t2 hi
+                                                               /* read t2 hi */
                        p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t2 lo
+                                                               /* read t2 lo */
                        p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t1 hi
+                                                               /* read t1 hi */
                        p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t1 lo
+                                                               /* read t1 lo */
                        p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t0 hi
+                                                               /* read t0 hi */
                        p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-                                                               // read t0 lo
+                                                               /* read t0 lo */
                }
                if (!sbp.tb_enable) {
-                       DBG(printk(DEVNAME ": tb_intr shutdown\n"));
+                       pr_debug(DEVNAME ": tb_intr shutdown\n");
                        __raw_writeq(M_SCD_TRACE_CFG_RESET,
                                     IOADDR(A_SCD_TRACE_CFG));
                        sbp.tb_armed = 0;
                        wake_up(&sbp.tb_sync);
                } else {
-                       arm_tb();       // knock down current interrupt and get another one later
+                       arm_tb();       /* knock down current interrupt and get another one later */
                }
        } else {
                /* No more trace buffer samples */
-               DBG(printk(DEVNAME ": tb_intr full\n"));
+               pr_debug(DEVNAME ": tb_intr full\n");
                __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
                sbp.tb_armed = 0;
                if (!sbp.tb_enable) {
@@ -135,6 +221,7 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
                }
                wake_up(&sbp.tb_read);
        }
+
        return IRQ_HANDLED;
 }
 
@@ -144,23 +231,30 @@ static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-int sbprof_zbprof_start(struct file *filp)
+/*
+ * Requires: Already called zclk_timer_init with a value that won't
+ *           saturate 40 bits.  No subsequent use of SCD performance counters
+ *           or trace buffer.
+ */
+
+static int sbprof_zbprof_start(struct file *filp)
 {
-       u_int64_t scdperfcnt;
+       u64 scdperfcnt;
+       int err;
 
-       if (sbp.tb_enable)
+       if (xchg(&sbp.tb_enable, 1))
                return -EBUSY;
 
-       DBG(printk(DEVNAME ": starting\n"));
+       pr_debug(DEVNAME ": starting\n");
 
-       sbp.tb_enable = 1;
        sbp.next_tb_sample = 0;
        filp->f_pos = 0;
 
-       if (request_irq
-           (K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, DEVNAME " trace freeze", &sbp)) {
+       err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0,
+                       DEVNAME " trace freeze", &sbp);
+       if (err)
                return -EBUSY;
-       }
+
        /* Make sure there isn't a perf-cnt interrupt waiting */
        scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
        /* Disable and clear counters, override SRC_1 */
@@ -168,18 +262,21 @@ int sbprof_zbprof_start(struct file *filp)
                     M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
                     IOADDR(A_SCD_PERF_CNT_CFG));
 
-       /* We grab this interrupt to prevent others from trying to use
-           it, even though we don't want to service the interrupts
-           (they only feed into the trace-on-interrupt mechanism) */
-       if (request_irq
-           (K_INT_PERF_CNT, sbprof_pc_intr, 0, DEVNAME " scd perfcnt", &sbp)) {
-               free_irq(K_INT_TRACE_FREEZE, &sbp);
-               return -EBUSY;
-       }
-
-       /* I need the core to mask these, but the interrupt mapper to
-          pass them through.  I am exploiting my knowledge that
-          cp0_status masks out IP[5]. krw */
+       /*
+        * We grab this interrupt to prevent others from trying to use it, even
+        * though we don't want to service the interrupts (they only feed into
+        * the trace-on-interrupt mechanism)
+        */
+       err = request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0,
+                       DEVNAME " scd perfcnt", &sbp);
+       if (err)
+               goto out_free_irq;
+
+       /*
+        * I need the core to mask these, but the interrupt mapper to pass them
+        * through.  I am exploiting my knowledge that cp0_status masks out
+        * IP[5]. krw
+        */
        __raw_writeq(K_INT_MAP_I3,
                     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
                            (K_INT_PERF_CNT << 3)));
@@ -201,7 +298,7 @@ int sbprof_zbprof_start(struct file *filp)
        __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
 
        /* Initialize Trace Event 0-7 */
-       //                              when interrupt
+       /*                              when interrupt */
        __raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
        __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
        __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
@@ -212,10 +309,10 @@ int sbprof_zbprof_start(struct file *filp)
        __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
 
        /* Initialize Trace Sequence 0-7 */
-       //                                   Start on event 0 (interrupt)
+       /*                                   Start on event 0 (interrupt) */
        __raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
                     IOADDR(A_SCD_TRACE_SEQUENCE_0));
-       //                        dsamp when d used | asamp when a used
+       /*                        dsamp when d used | asamp when a used */
        __raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
                     K_SCD_TRSEQ_TRIGGER_ALL,
                     IOADDR(A_SCD_TRACE_SEQUENCE_1));
@@ -232,33 +329,41 @@ int sbprof_zbprof_start(struct file *filp)
 
        arm_tb();
 
-       DBG(printk(DEVNAME ": done starting\n"));
+       pr_debug(DEVNAME ": done starting\n");
 
        return 0;
+
+out_free_irq:
+       free_irq(K_INT_TRACE_FREEZE, &sbp);
+
+       return err;
 }
 
-int sbprof_zbprof_stop(void)
+static int sbprof_zbprof_stop(void)
 {
-       DEFINE_WAIT(wait);
-       DBG(printk(DEVNAME ": stopping\n"));
+       int err;
+
+       pr_debug(DEVNAME ": stopping\n");
 
        if (sbp.tb_enable) {
+               /*
+                * XXXKW there is a window here where the intr handler may run,
+                * see the disable, and do the wake_up before this sleep
+                * happens.
+                */
+               pr_debug(DEVNAME ": wait for disarm\n");
+               err = wait_event_interruptible(sbp.tb_sync, !sbp.tb_armed);
+               pr_debug(DEVNAME ": disarm complete, stat %d\n", err);
+
+               if (err)
+                       return err;
+
                sbp.tb_enable = 0;
-               /* XXXKW there is a window here where the intr handler
-                  may run, see the disable, and do the wake_up before
-                  this sleep happens. */
-               if (sbp.tb_armed) {
-                       DBG(printk(DEVNAME ": wait for disarm\n"));
-                       prepare_to_wait(&sbp.tb_sync, &wait, TASK_INTERRUPTIBLE);
-                       schedule();
-                       finish_wait(&sbp.tb_sync, &wait);
-                       DBG(printk(DEVNAME ": disarm complete\n"));
-               }
                free_irq(K_INT_TRACE_FREEZE, &sbp);
                free_irq(K_INT_PERF_CNT, &sbp);
        }
 
-       DBG(printk(DEVNAME ": done stopping\n"));
+       pr_debug(DEVNAME ": done stopping\n");
 
        return 0;
 }
@@ -268,42 +373,45 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp)
        int minor;
 
        minor = iminor(inode);
-       if (minor != 0) {
+       if (minor != 0)
                return -ENODEV;
-       }
-       if (sbp.open) {
+
+       if (xchg(&sbp.open, SB_OPENING) != SB_CLOSED)
                return -EBUSY;
-       }
 
        memset(&sbp, 0, sizeof(struct sbprof_tb));
+
        sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES);
-       if (!sbp.sbprof_tbbuf) {
+       if (!sbp.sbprof_tbbuf)
                return -ENOMEM;
-       }
+
        memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES);
        init_waitqueue_head(&sbp.tb_sync);
        init_waitqueue_head(&sbp.tb_read);
-       sbp.open = 1;
+       mutex_init(&sbp.lock);
+
+       sbp.open = SB_OPEN;
 
        return 0;
 }
 
 static int sbprof_tb_release(struct inode *inode, struct file *filp)
 {
-       int minor;
+       int minor = iminor(inode);
 
-       minor = iminor(inode);
-       if (minor != 0 || !sbp.open) {
+       if (minor != 0 || !sbp.open)
                return -ENODEV;
-       }
 
-       if (sbp.tb_armed || sbp.tb_enable) {
+       mutex_lock(&sbp.lock);
+
+       if (sbp.tb_armed || sbp.tb_enable)
                sbprof_zbprof_stop();
-       }
 
        vfree(sbp.sbprof_tbbuf);
        sbp.open = 0;
 
+       mutex_unlock(&sbp.lock);
+
        return 0;
 }
 
@@ -311,21 +419,35 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf,
                              size_t size, loff_t *offp)
 {
        int cur_sample, sample_off, cur_count, sample_left;
-       char *src;
-       int   count   =  0;
-       char *dest    =  buf;
        long  cur_off = *offp;
+       char *dest    =  buf;
+       int   count   =  0;
+       char *src;
+
+       if (!access_ok(VERIFY_WRITE, buf, size))
+               return -EFAULT;
+
+       mutex_lock(&sbp.lock);
 
        count = 0;
        cur_sample = cur_off / TB_SAMPLE_SIZE;
        sample_off = cur_off % TB_SAMPLE_SIZE;
        sample_left = TB_SAMPLE_SIZE - sample_off;
+
        while (size && (cur_sample < sbp.next_tb_sample)) {
+               int err;
+
                cur_count = size < sample_left ? size : sample_left;
                src = (char *)(((long)sbp.sbprof_tbbuf[cur_sample])+sample_off);
-               copy_to_user(dest, src, cur_count);
-               DBG(printk(DEVNAME ": read from sample %d, %d bytes\n",
-                          cur_sample, cur_count));
+               err = __copy_to_user(dest, src, cur_count);
+               if (err) {
+                       *offp = cur_off + cur_count - err;
+                       mutex_unlock(&sbp.lock);
+                       return err;
+               }
+
+               pr_debug(DEVNAME ": read from sample %d, %d bytes\n",
+                        cur_sample, cur_count);
                size -= cur_count;
                sample_left -= cur_count;
                if (!sample_left) {
@@ -339,37 +461,43 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf,
                dest += cur_count;
                count += cur_count;
        }
+
        *offp = cur_off;
+       mutex_unlock(&sbp.lock);
 
        return count;
 }
 
-static long sbprof_tb_ioctl(struct file *filp,
-                           unsigned int command,
-                           unsigned long arg)
+static long sbprof_tb_ioctl(struct file *filp, unsigned int command,
+       unsigned long arg)
 {
        int error = 0;
 
-       lock_kernel();
        switch (command) {
        case SBPROF_ZBSTART:
+               mutex_lock(&sbp.lock);
                error = sbprof_zbprof_start(filp);
+               mutex_unlock(&sbp.lock);
                break;
+
        case SBPROF_ZBSTOP:
+               mutex_lock(&sbp.lock);
                error = sbprof_zbprof_stop();
+               mutex_unlock(&sbp.lock);
                break;
+
        case SBPROF_ZBWAITFULL:
-               DEFINE_WAIT(wait);
-               prepare_to_wait(&sbp.tb_read, &wait, TASK_INTERRUPTIBLE);
-               schedule();
-               finish_wait(&sbp.tb_read, &wait);
-               /* XXXKW check if interrupted? */
-               return put_user(TB_FULL, (int *) arg);
+               error = wait_event_interruptible(sbp.tb_read, TB_FULL);
+               if (error)
+                       break;
+
+               error = put_user(TB_FULL, (int *) arg);
+               break;
+
        default:
                error = -EINVAL;
                break;
        }
-       unlock_kernel();
 
        return error;
 }
@@ -384,23 +512,60 @@ static const struct file_operations sbprof_tb_fops = {
        .mmap           = NULL,
 };
 
+static struct class *tb_class;
+static struct device *tb_dev;
+
 static int __init sbprof_tb_init(void)
 {
+       struct device *dev;
+       struct class *tbc;
+       int err;
+
        if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
                printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
                       SBPROF_TB_MAJOR);
                return -EIO;
        }
+
+       tbc = class_create(THIS_MODULE, "sb_tracebuffer");
+       if (IS_ERR(tbc)) {
+               err = PTR_ERR(tbc);
+               goto out_chrdev;
+       }
+
+       tb_class = tbc;
+
+       dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), "tb");
+       if (IS_ERR(dev)) {
+               err = PTR_ERR(dev);
+               goto out_class;
+       }
+       tb_dev = dev;
+
        sbp.open = 0;
        tb_period = zbbus_mhz * 10000LL;
-       printk(KERN_INFO DEVNAME ": initialized - tb_period = %lld\n", tb_period);
+       pr_info(DEVNAME ": initialized - tb_period = %lld\n", tb_period);
+
        return 0;
+
+out_class:
+       class_destroy(tb_class);
+out_chrdev:
+       unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+
+       return err;
 }
 
 static void __exit sbprof_tb_cleanup(void)
 {
+       device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0));
        unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+       class_destroy(tb_class);
 }
 
 module_init(sbprof_tb_init);
 module_exit(sbprof_tb_cleanup);
+
+MODULE_ALIAS_CHARDEV_MAJOR(SBPROF_TB_MAJOR);
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_LICENSE("GPL");
index 1cb042e..87188f0 100644 (file)
@@ -16,6 +16,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/reboot.h>
 #include <linux/string.h>
@@ -32,6 +33,7 @@ unsigned int soc_pass;
 unsigned int soc_type;
 unsigned int periph_rev;
 unsigned int zbbus_mhz;
+EXPORT_SYMBOL(zbbus_mhz);
 
 static char *soc_str;
 static char *pass_str;
diff --git a/include/asm-mips/sibyte/trace_prof.h b/include/asm-mips/sibyte/trace_prof.h
deleted file mode 100644 (file)
index 5577920..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#ifndef __ASM_SIBYTE_TRACE_PROF_H
-#define __ASM_SIBYTE_TRACE_PROF_H
-
-#undef DBG
-#if SBPROF_TB_DEBUG
-#define DBG(a) a
-#else
-#define DBG(a)
-#endif
-
-#define SBPROF_TB_MAJOR 240
-#define DEVNAME "bcm1250_tbprof"
-
-typedef u_int64_t tb_sample_t[6*256];
-
-struct sbprof_tb {
-       int          open;
-       tb_sample_t *sbprof_tbbuf;
-       int          next_tb_sample;
-
-       volatile int tb_enable;
-       volatile int tb_armed;
-
-       wait_queue_head_t tb_sync;
-       wait_queue_head_t tb_read;
-};
-
-#define MAX_SAMPLE_BYTES (24*1024*1024)
-#define MAX_TBSAMPLE_BYTES (12*1024*1024)
-
-#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
-#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
-#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
-
-/* IOCTLs */
-#define SBPROF_ZBSTART         _IOW('s', 0, int)
-#define SBPROF_ZBSTOP          _IOW('s', 1, int)
-#define SBPROF_ZBWAITFULL      _IOW('s', 2, int)
-
-/***************************************************************************
- * Routines for gathering ZBbus profiles using trace buffer
- ***************************************************************************/
-
-/* Requires: Already called zclk_timer_init with a value that won't
-            saturate 40 bits.  No subsequent use of SCD performance counters
-            or trace buffer.
-   Effect:   Starts gathering random ZBbus profiles using trace buffer. */
-extern int sbprof_zbprof_start(struct file *filp);
-
-/* Effect: Stops collection of ZBbus profiles */
-extern int sbprof_zbprof_stop(void);
-
-
-/***************************************************************************
- * Routines for using 40-bit SCD cycle counter
- *
- * Client responsible for either handling interrupts or making sure
- * the cycles counter never saturates, e.g., by doing
- * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
- ***************************************************************************/
-
-/* Configures SCD counter 0 to count ZCLKs starting from val;
-   Configures SCD counters1,2,3 to count nothing.
-   Must not be called while gathering ZBbus profiles.
-
-unsigned long long val; */
-#define zclk_timer_init(val) \
-  __asm__ __volatile__ (".set push;" \
-                       ".set mips64;" \
-                       "la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
-                       "sd   %0, 0x10($8);"   /* write val to counter0 */ \
-                       "sd   %1, 0($8);"      /* config counter0 for zclks*/ \
-                       ".set pop" \
-                       : /* no outputs */ \
-                                                    /* enable, counter0 */ \
-                       : /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
-                       : /* modifies */ "$8" )
-
-
-/* Reads SCD counter 0 and puts result in value
-   unsigned long long val; */
-#define zclk_get(val) \
-  __asm__ __volatile__ (".set push;" \
-                       ".set mips64;" \
-                       "la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
-                       "ld   %0, 0x10($8);"   /* write val to counter0 */ \
-                       ".set pop" \
-                       : /* outputs */ "=r"(val) \
-                       : /* inputs */ \
-                       : /* modifies */ "$8" )
-
-#endif /* __ASM_SIBYTE_TRACE_PROF_H */