~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/sgi-ip22/ip28-berr.c

Version: ~ [ linux-5.16-rc1 ] ~ [ linux-5.15.2 ] ~ [ linux-5.14.18 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.79 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.159 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.217 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.255 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.290 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.292 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * ip28-berr.c: Bus error handling.
  4  *
  5  * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org)
  6  * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28
  7  */
  8 
  9 #include <linux/init.h>
 10 #include <linux/kernel.h>
 11 #include <linux/mm.h>
 12 #include <linux/sched.h>
 13 #include <linux/sched/debug.h>
 14 #include <linux/sched/signal.h>
 15 #include <linux/seq_file.h>
 16 
 17 #include <asm/addrspace.h>
 18 #include <asm/traps.h>
 19 #include <asm/branch.h>
 20 #include <asm/irq_regs.h>
 21 #include <asm/sgi/mc.h>
 22 #include <asm/sgi/hpc3.h>
 23 #include <asm/sgi/ioc.h>
 24 #include <asm/sgi/ip22.h>
 25 #include <asm/r4kcache.h>
 26 #include <linux/uaccess.h>
 27 #include <asm/bootinfo.h>
 28 
 29 static unsigned int count_be_is_fixup;
 30 static unsigned int count_be_handler;
 31 static unsigned int count_be_interrupt;
 32 static int debug_be_interrupt;
 33 
 34 static unsigned int cpu_err_stat;       /* Status reg for CPU */
 35 static unsigned int gio_err_stat;       /* Status reg for GIO */
 36 static unsigned int cpu_err_addr;       /* Error address reg for CPU */
 37 static unsigned int gio_err_addr;       /* Error address reg for GIO */
 38 static unsigned int extio_stat;
 39 static unsigned int hpc3_berr_stat;     /* Bus error interrupt status */
 40 
 41 struct hpc3_stat {
 42         unsigned long addr;
 43         unsigned int ctrl;
 44         unsigned int cbp;
 45         unsigned int ndptr;
 46 };
 47 
 48 static struct {
 49         struct hpc3_stat pbdma[8];
 50         struct hpc3_stat scsi[2];
 51         struct hpc3_stat ethrx, ethtx;
 52 } hpc3;
 53 
 54 static struct {
 55         unsigned long err_addr;
 56         struct {
 57                 u32 lo;
 58                 u32 hi;
 59         } tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */
 60 } cache_tags;
 61 
 62 static inline void save_cache_tags(unsigned busaddr)
 63 {
 64         unsigned long addr = CAC_BASE | busaddr;
 65         int i;
 66         cache_tags.err_addr = addr;
 67 
 68         /*
 69          * Starting with a bus-address, save secondary cache (indexed by
 70          * PA[23..18:7..6]) tags first.
 71          */
 72         addr &= ~1L;
 73 #define tag cache_tags.tags[0]
 74         cache_op(Index_Load_Tag_S, addr);
 75         tag[0].lo = read_c0_taglo();    /* PA[35:18], VA[13:12] */
 76         tag[0].hi = read_c0_taghi();    /* PA[39:36] */
 77         cache_op(Index_Load_Tag_S, addr | 1L);
 78         tag[1].lo = read_c0_taglo();    /* PA[35:18], VA[13:12] */
 79         tag[1].hi = read_c0_taghi();    /* PA[39:36] */
 80 #undef tag
 81 
 82         /*
 83          * Save all primary data cache (indexed by VA[13:5]) tags which
 84          * might fit to this bus-address, knowing that VA[11:0] == PA[11:0].
 85          * Saving all tags and evaluating them later is easier and safer
 86          * than relying on VA[13:12] from the secondary cache tags to pick
 87          * matching primary tags here already.
 88          */
 89         addr &= (0xffL << 56) | ((1 << 12) - 1);
 90 #define tag cache_tags.tagd[i]
 91         for (i = 0; i < 4; ++i, addr += (1 << 12)) {
 92                 cache_op(Index_Load_Tag_D, addr);
 93                 tag[0].lo = read_c0_taglo();    /* PA[35:12] */
 94                 tag[0].hi = read_c0_taghi();    /* PA[39:36] */
 95                 cache_op(Index_Load_Tag_D, addr | 1L);
 96                 tag[1].lo = read_c0_taglo();    /* PA[35:12] */
 97                 tag[1].hi = read_c0_taghi();    /* PA[39:36] */
 98         }
 99 #undef tag
100 
101         /*
102          * Save primary instruction cache (indexed by VA[13:6]) tags
103          * the same way.
104          */
105         addr &= (0xffL << 56) | ((1 << 12) - 1);
106 #define tag cache_tags.tagi[i]
107         for (i = 0; i < 4; ++i, addr += (1 << 12)) {
108                 cache_op(Index_Load_Tag_I, addr);
109                 tag[0].lo = read_c0_taglo();    /* PA[35:12] */
110                 tag[0].hi = read_c0_taghi();    /* PA[39:36] */
111                 cache_op(Index_Load_Tag_I, addr | 1L);
112                 tag[1].lo = read_c0_taglo();    /* PA[35:12] */
113                 tag[1].hi = read_c0_taghi();    /* PA[39:36] */
114         }
115 #undef tag
116 }
117 
118 #define GIO_ERRMASK     0xff00
119 #define CPU_ERRMASK     0x3f00
120 
121 static void save_and_clear_buserr(void)
122 {
123         int i;
124 
125         /* save status registers */
126         cpu_err_addr = sgimc->cerr;
127         cpu_err_stat = sgimc->cstat;
128         gio_err_addr = sgimc->gerr;
129         gio_err_stat = sgimc->gstat;
130         extio_stat = sgioc->extio;
131         hpc3_berr_stat = hpc3c0->bestat;
132 
133         hpc3.scsi[0].addr  = (unsigned long)&hpc3c0->scsi_chan0;
134         hpc3.scsi[0].ctrl  = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */
135         hpc3.scsi[0].cbp   = hpc3c0->scsi_chan0.cbptr;
136         hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr;
137 
138         hpc3.scsi[1].addr  = (unsigned long)&hpc3c0->scsi_chan1;
139         hpc3.scsi[1].ctrl  = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */
140         hpc3.scsi[1].cbp   = hpc3c0->scsi_chan1.cbptr;
141         hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr;
142 
143         hpc3.ethrx.addr  = (unsigned long)&hpc3c0->ethregs.rx_cbptr;
144         hpc3.ethrx.ctrl  = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */
145         hpc3.ethrx.cbp   = hpc3c0->ethregs.rx_cbptr;
146         hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr;
147 
148         hpc3.ethtx.addr  = (unsigned long)&hpc3c0->ethregs.tx_cbptr;
149         hpc3.ethtx.ctrl  = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */
150         hpc3.ethtx.cbp   = hpc3c0->ethregs.tx_cbptr;
151         hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr;
152 
153         for (i = 0; i < 8; ++i) {
154                 /* HPC3_PDMACTRL_ISACT ? */
155                 hpc3.pbdma[i].addr  = (unsigned long)&hpc3c0->pbdma[i];
156                 hpc3.pbdma[i].ctrl  = hpc3c0->pbdma[i].pbdma_ctrl;
157                 hpc3.pbdma[i].cbp   = hpc3c0->pbdma[i].pbdma_bptr;
158                 hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr;
159         }
160         i = 0;
161         if (gio_err_stat & CPU_ERRMASK)
162                 i = gio_err_addr;
163         if (cpu_err_stat & CPU_ERRMASK)
164                 i = cpu_err_addr;
165         save_cache_tags(i);
166 
167         sgimc->cstat = sgimc->gstat = 0;
168 }
169 
170 static void print_cache_tags(void)
171 {
172         u32 scb, scw;
173         int i;
174 
175         printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr);
176 
177         /* PA[31:12] shifted to PTag0 (PA[35:12]) format */
178         scw = (cache_tags.err_addr >> 4) & 0x0fffff00;
179 
180         scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1);
181         for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
182                 if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw &&
183                     (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw)
184                     continue;
185                 printk(KERN_ERR
186                        "D: 0: %08x %08x, 1: %08x %08x  (VA[13:5]  %04x)\n",
187                         cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo,
188                         cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo,
189                         scb | (1 << 12)*i);
190         }
191         scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1);
192         for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
193                 if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw &&
194                     (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw)
195                     continue;
196                 printk(KERN_ERR
197                        "I: 0: %08x %08x, 1: %08x %08x  (VA[13:6]  %04x)\n",
198                         cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo,
199                         cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo,
200                         scb | (1 << 12)*i);
201         }
202         i = read_c0_config();
203         scb = i & (1 << 13) ? 7:6;      /* scblksize = 2^[7..6] */
204         scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */
205 
206         i = ((1 << scw) - 1) & ~((1 << scb) - 1);
207         printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x  (PA[%u:%u] %05x)\n",
208                 cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo,
209                 cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo,
210                 scw-1, scb, i & (unsigned)cache_tags.err_addr);
211 }
212 
213 static inline const char *cause_excode_text(int cause)
214 {
215         static const char *txt[32] =
216         {       "Interrupt",
217                 "TLB modification",
218                 "TLB (load or instruction fetch)",
219                 "TLB (store)",
220                 "Address error (load or instruction fetch)",
221                 "Address error (store)",
222                 "Bus error (instruction fetch)",
223                 "Bus error (data: load or store)",
224                 "Syscall",
225                 "Breakpoint",
226                 "Reserved instruction",
227                 "Coprocessor unusable",
228                 "Arithmetic Overflow",
229                 "Trap",
230                 "14",
231                 "Floating-Point",
232                 "16", "17", "18", "19", "20", "21", "22",
233                 "Watch Hi/Lo",
234                 "24", "25", "26", "27", "28", "29", "30", "31",
235         };
236         return txt[(cause & 0x7c) >> 2];
237 }
238 
239 static void print_buserr(const struct pt_regs *regs)
240 {
241         const int field = 2 * sizeof(unsigned long);
242         int error = 0;
243 
244         if (extio_stat & EXTIO_MC_BUSERR) {
245                 printk(KERN_ERR "MC Bus Error\n");
246                 error |= 1;
247         }
248         if (extio_stat & EXTIO_HPC3_BUSERR) {
249                 printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n",
250                         hpc3_berr_stat,
251                         (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >>
252                                           HPC3_BESTAT_PIDSHIFT,
253                         (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA",
254                         hpc3_berr_stat & HPC3_BESTAT_BLMASK);
255                 error |= 2;
256         }
257         if (extio_stat & EXTIO_EISA_BUSERR) {
258                 printk(KERN_ERR "EISA Bus Error\n");
259                 error |= 4;
260         }
261         if (cpu_err_stat & CPU_ERRMASK) {
262                 printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n",
263                         cpu_err_stat,
264                         cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "",
265                         cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "",
266                         cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "",
267                         cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "",
268                         cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "",
269                         cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
270                         cpu_err_addr);
271                 error |= 8;
272         }
273         if (gio_err_stat & GIO_ERRMASK) {
274                 printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
275                         gio_err_stat,
276                         gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
277                         gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
278                         gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "",
279                         gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "",
280                         gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "",
281                         gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "",
282                         gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "",
283                         gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "",
284                         gio_err_addr);
285                 error |= 16;
286         }
287         if (!error)
288                 printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n");
289         else {
290                 printk(KERN_ERR "CP0: config %08x,  "
291                         "MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n"
292                         "MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n",
293                         read_c0_config(),
294                         sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar,
295                         sgimc->cmacc, sgimc->gmacc,
296                         sgimc->mconfig0, sgimc->mconfig1);
297                 print_cache_tags();
298         }
299         printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n",
300                cause_excode_text(regs->cp0_cause),
301                field, regs->cp0_epc, field, regs->regs[31]);
302 }
303 
304 static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr)
305 {
306         /* This is likely rather similar to correct code ;-) */
307 
308         vaddr &= 0x7fffffff; /* Doc. states that top bit is ignored */
309 
310         /* If tlb-entry is valid and VPN-high (bits [30:21] ?) matches... */
311         if ((lo & 2) && (vaddr >> 21) == ((hi<<1) >> 22)) {
312                 u32 ctl = sgimc->dma_ctrl;
313                 if (ctl & 1) {
314                         unsigned int pgsz = (ctl & 2) ? 14:12; /* 16k:4k */
315                         /* PTEIndex is VPN-low (bits [22:14]/[20:12] ?) */
316                         unsigned long pte = (lo >> 6) << 12; /* PTEBase */
317                         pte += 8*((vaddr >> pgsz) & 0x1ff);
318                         if (page_is_ram(PFN_DOWN(pte))) {
319                                 /*
320                                  * Note: Since DMA hardware does look up
321                                  * translation on its own, this PTE *must*
322                                  * match the TLB/EntryLo-register format !
323                                  */
324                                 unsigned long a = *(unsigned long *)
325                                                 PHYS_TO_XKSEG_UNCACHED(pte);
326                                 a = (a & 0x3f) << 6; /* PFN */
327                                 a += vaddr & ((1 << pgsz) - 1);
328                                 return cpu_err_addr == a;
329                         }
330                 }
331         }
332         return 0;
333 }
334 
335 static int check_vdma_memaddr(void)
336 {
337         if (cpu_err_stat & CPU_ERRMASK) {
338                 u32 a = sgimc->maddronly;
339 
340                 if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */
341                         return cpu_err_addr == a;
342 
343                 if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) ||
344                     check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) ||
345                     check_microtlb(sgimc->dtlb_hi2, sgimc->dtlb_lo2, a) ||
346                     check_microtlb(sgimc->dtlb_hi3, sgimc->dtlb_lo3, a))
347                         return 1;
348         }
349         return 0;
350 }
351 
352 static int check_vdma_gioaddr(void)
353 {
354         if (gio_err_stat & GIO_ERRMASK) {
355                 u32 a = sgimc->gio_dma_trans;
356                 a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a);
357                 return gio_err_addr == a;
358         }
359         return 0;
360 }
361 
362 /*
363  * MC sends an interrupt whenever bus or parity errors occur. In addition,
364  * if the error happened during a CPU read, it also asserts the bus error
365  * pin on the R4K. Code in bus error handler save the MC bus error registers
366  * and then clear the interrupt when this happens.
367  */
368 
369 static int ip28_be_interrupt(const struct pt_regs *regs)
370 {
371         int i;
372 
373         save_and_clear_buserr();
374         /*
375          * Try to find out, whether we got here by a mispredicted speculative
376          * load/store operation.  If so, it's not fatal, we can go on.
377          */
378         /* Any cause other than "Interrupt" (ExcCode 0) is fatal. */
379         if (regs->cp0_cause & CAUSEF_EXCCODE)
380                 goto mips_be_fatal;
381 
382         /* Any cause other than "Bus error interrupt" (IP6) is weird. */
383         if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6)
384                 goto mips_be_fatal;
385 
386         if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR))
387                 goto mips_be_fatal;
388 
389         /* Any state other than "Memory bus error" is fatal. */
390         if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR)
391                 goto mips_be_fatal;
392 
393         /* GIO errors other than timeouts are fatal */
394         if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME)
395                 goto mips_be_fatal;
396 
397         /*
398          * Now we have an asynchronous bus error, speculatively or DMA caused.
399          * Need to search all DMA descriptors for the error address.
400          */
401         for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) {
402                 struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
403                 if ((cpu_err_stat & CPU_ERRMASK) &&
404                     (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp))
405                         break;
406                 if ((gio_err_stat & GIO_ERRMASK) &&
407                     (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp))
408                         break;
409         }
410         if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) {
411                 struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
412                 printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:"
413                        " ctl %08x, ndp %08x, cbp %08x\n",
414                        CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp);
415                 goto mips_be_fatal;
416         }
417         /* Check MC's virtual DMA stuff. */
418         if (check_vdma_memaddr()) {
419                 printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n",
420                         sgimc->maddronly);
421                 goto mips_be_fatal;
422         }
423         if (check_vdma_gioaddr()) {
424                 printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n",
425                         sgimc->gmaddronly);
426                 goto mips_be_fatal;
427         }
428         /* A speculative bus error... */
429         if (debug_be_interrupt) {
430                 print_buserr(regs);
431                 printk(KERN_ERR "discarded!\n");
432         }
433         return MIPS_BE_DISCARD;
434 
435 mips_be_fatal:
436         print_buserr(regs);
437         return MIPS_BE_FATAL;
438 }
439 
440 void ip22_be_interrupt(int irq)
441 {
442         struct pt_regs *regs = get_irq_regs();
443 
444         count_be_interrupt++;
445 
446         if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) {
447                 /* Assume it would be too dangerous to continue ... */
448                 die_if_kernel("Oops", regs);
449                 force_sig(SIGBUS);
450         } else if (debug_be_interrupt)
451                 show_regs(regs);
452 }
453 
454 static int ip28_be_handler(struct pt_regs *regs, int is_fixup)
455 {
456         /*
457          * We arrive here only in the unusual case of do_be() invocation,
458          * i.e. by a bus error exception without a bus error interrupt.
459          */
460         if (is_fixup) {
461                 count_be_is_fixup++;
462                 save_and_clear_buserr();
463                 return MIPS_BE_FIXUP;
464         }
465         count_be_handler++;
466         return ip28_be_interrupt(regs);
467 }
468 
469 void __init ip22_be_init(void)
470 {
471         board_be_handler = ip28_be_handler;
472 }
473 
474 int ip28_show_be_info(struct seq_file *m)
475 {
476         seq_printf(m, "IP28 be fixups\t\t: %u\n", count_be_is_fixup);
477         seq_printf(m, "IP28 be interrupts\t: %u\n", count_be_interrupt);
478         seq_printf(m, "IP28 be handler\t\t: %u\n", count_be_handler);
479 
480         return 0;
481 }
482 
483 static int __init debug_be_setup(char *str)
484 {
485         debug_be_interrupt++;
486         return 1;
487 }
488 __setup("ip28_debug_be", debug_be_setup);
489 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp