0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/init.h>
0016 #include <linux/kernel.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/sched.h>
0019 #include <linux/proc_fs.h>
0020 #include <linux/seq_file.h>
0021 #include <asm/io.h>
0022
0023 #include <asm/sibyte/sb1250.h>
0024 #include <asm/sibyte/sb1250_regs.h>
0025 #include <asm/sibyte/sb1250_int.h>
0026 #include <asm/sibyte/sb1250_scd.h>
0027 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
0028 #include <asm/sibyte/bcm1480_regs.h>
0029 #endif
0030
0031
0032 struct bw_stats_struct {
0033 uint64_t status;
0034 uint32_t l2_err;
0035 uint32_t memio_err;
0036 int status_printed;
0037 unsigned long l2_cor_d;
0038 unsigned long l2_bad_d;
0039 unsigned long l2_cor_t;
0040 unsigned long l2_bad_t;
0041 unsigned long mem_cor_d;
0042 unsigned long mem_bad_d;
0043 unsigned long bus_error;
0044 } bw_stats;
0045
0046
0047 static void print_summary(uint32_t status, uint32_t l2_err,
0048 uint32_t memio_err)
0049 {
0050 printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
0051 printk("\nLast recorded signature:\n");
0052 printk("Request %02x from %d, answered by %d with Dcode %d\n",
0053 (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
0054 (int)(G_SCD_BERR_TID(status) >> 6),
0055 (int)G_SCD_BERR_RID(status),
0056 (int)G_SCD_BERR_DCODE(status));
0057 }
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 void check_bus_watcher(void)
0068 {
0069 u32 status, l2_err, memio_err;
0070
0071 #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
0072
0073 status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
0074 #elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
0075
0076
0077 status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG));
0078 #else
0079 #error bus watcher being built for unknown Sibyte SOC!
0080 #endif
0081 if (!(status & 0x7fffffff)) {
0082 printk("Using last values reaped by bus watcher driver\n");
0083 status = bw_stats.status;
0084 l2_err = bw_stats.l2_err;
0085 memio_err = bw_stats.memio_err;
0086 } else {
0087 l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
0088 memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
0089 }
0090 if (status & ~(1UL << 31))
0091 print_summary(status, l2_err, memio_err);
0092 else
0093 printk("Bus watcher indicates no error\n");
0094 }
0095
0096 #ifdef CONFIG_PROC_FS
0097
0098
0099
0100 static int bw_proc_show(struct seq_file *m, void *v)
0101 {
0102 struct bw_stats_struct *stats = m->private;
0103
0104 seq_puts(m, "SiByte Bus Watcher statistics\n");
0105 seq_puts(m, "-----------------------------\n");
0106 seq_printf(m, "L2-d-cor %8ld\nL2-d-bad %8ld\n",
0107 stats->l2_cor_d, stats->l2_bad_d);
0108 seq_printf(m, "L2-t-cor %8ld\nL2-t-bad %8ld\n",
0109 stats->l2_cor_t, stats->l2_bad_t);
0110 seq_printf(m, "MC-d-cor %8ld\nMC-d-bad %8ld\n",
0111 stats->mem_cor_d, stats->mem_bad_d);
0112 seq_printf(m, "IO-err %8ld\n", stats->bus_error);
0113 seq_puts(m, "\nLast recorded signature:\n");
0114 seq_printf(m, "Request %02x from %d, answered by %d with Dcode %d\n",
0115 (unsigned int)(G_SCD_BERR_TID(stats->status) & 0x3f),
0116 (int)(G_SCD_BERR_TID(stats->status) >> 6),
0117 (int)G_SCD_BERR_RID(stats->status),
0118 (int)G_SCD_BERR_DCODE(stats->status));
0119
0120
0121 if (stats->status & M_SCD_BERR_MULTERRS)
0122 seq_puts(m, "Multiple errors observed since last check.\n");
0123 if (stats->status_printed) {
0124 seq_puts(m, "(no change since last printing)\n");
0125 } else {
0126 stats->status_printed = 1;
0127 }
0128
0129 return 0;
0130 }
0131
0132 static void create_proc_decoder(struct bw_stats_struct *stats)
0133 {
0134 struct proc_dir_entry *ent;
0135
0136 ent = proc_create_single_data("bus_watcher", S_IWUSR | S_IRUGO, NULL,
0137 bw_proc_show, stats);
0138 if (!ent) {
0139 printk(KERN_INFO "Unable to initialize bus_watcher /proc entry\n");
0140 return;
0141 }
0142 }
0143
0144 #endif
0145
0146
0147
0148
0149
0150
0151
0152 static irqreturn_t sibyte_bw_int(int irq, void *data)
0153 {
0154 struct bw_stats_struct *stats = data;
0155 unsigned long cntr;
0156 #ifdef CONFIG_SIBYTE_BW_TRACE
0157 int i;
0158 #endif
0159
0160 #ifdef CONFIG_SIBYTE_BW_TRACE
0161 csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
0162 csr_out32(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG));
0163
0164 for (i=0; i<256*6; i++)
0165 printk("%016llx\n",
0166 (long long)__raw_readq(IOADDR(A_SCD_TRACE_READ)));
0167
0168 csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
0169 csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
0170 #endif
0171
0172
0173 stats->status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
0174 stats->status_printed = 0;
0175
0176 stats->l2_err = cntr = csr_in32(IOADDR(A_BUS_L2_ERRORS));
0177 stats->l2_cor_d += G_SCD_L2ECC_CORR_D(cntr);
0178 stats->l2_bad_d += G_SCD_L2ECC_BAD_D(cntr);
0179 stats->l2_cor_t += G_SCD_L2ECC_CORR_T(cntr);
0180 stats->l2_bad_t += G_SCD_L2ECC_BAD_T(cntr);
0181 csr_out32(0, IOADDR(A_BUS_L2_ERRORS));
0182
0183 stats->memio_err = cntr = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
0184 stats->mem_cor_d += G_SCD_MEM_ECC_CORR(cntr);
0185 stats->mem_bad_d += G_SCD_MEM_ECC_BAD(cntr);
0186 stats->bus_error += G_SCD_MEM_BUSERR(cntr);
0187 csr_out32(0, IOADDR(A_BUS_MEM_IO_ERRORS));
0188
0189 return IRQ_HANDLED;
0190 }
0191
0192 int __init sibyte_bus_watcher(void)
0193 {
0194 memset(&bw_stats, 0, sizeof(struct bw_stats_struct));
0195 bw_stats.status_printed = 1;
0196
0197 if (request_irq(K_INT_BAD_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
0198 printk("Failed to register bus watcher BAD_ECC irq\n");
0199 return -1;
0200 }
0201 if (request_irq(K_INT_COR_ECC, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
0202 free_irq(K_INT_BAD_ECC, &bw_stats);
0203 printk("Failed to register bus watcher COR_ECC irq\n");
0204 return -1;
0205 }
0206 if (request_irq(K_INT_IO_BUS, sibyte_bw_int, 0, "Bus watcher", &bw_stats)) {
0207 free_irq(K_INT_BAD_ECC, &bw_stats);
0208 free_irq(K_INT_COR_ECC, &bw_stats);
0209 printk("Failed to register bus watcher IO_BUS irq\n");
0210 return -1;
0211 }
0212
0213 #ifdef CONFIG_PROC_FS
0214 create_proc_decoder(&bw_stats);
0215 #endif
0216
0217 #ifdef CONFIG_SIBYTE_BW_TRACE
0218 csr_out32((M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
0219 K_SCD_TRSEQ_TRIGGER_ALL),
0220 IOADDR(A_SCD_TRACE_SEQUENCE_0));
0221 csr_out32(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
0222 csr_out32(M_SCD_TRACE_CFG_START, IOADDR(A_SCD_TRACE_CFG));
0223 #endif
0224
0225 return 0;
0226 }
0227
0228 device_initcall(sibyte_bus_watcher);