root/arch/m68k/mm/hwtest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hwreg_present
  2. hwreg_write

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Tests for presence or absence of hardware registers.
   3  * This code was originally in atari/config.c, but I noticed
   4  * that it was also in drivers/nubus/nubus.c and I wanted to
   5  * use it in hp300/config.c, so it seemed sensible to pull it
   6  * out into its own file.
   7  *
   8  * The test is for use when trying to read a hardware register
   9  * that isn't present would cause a bus error. We set up a
  10  * temporary handler so that this doesn't kill the kernel.
  11  *
  12  * There is a test-by-reading and a test-by-writing; I present
  13  * them here complete with the comments from the original atari
  14  * config.c...
  15  *                -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998
  16  */
  17 
  18 /* This function tests for the presence of an address, specially a
  19  * hardware register address. It is called very early in the kernel
  20  * initialization process, when the VBR register isn't set up yet. On
  21  * an Atari, it still points to address 0, which is unmapped. So a bus
  22  * error would cause another bus error while fetching the exception
  23  * vector, and the CPU would do nothing at all. So we needed to set up
  24  * a temporary VBR and a vector table for the duration of the test.
  25  */
  26 
  27 #include <linux/module.h>
  28 
  29 int hwreg_present(volatile void *regp)
  30 {
  31         int ret = 0;
  32         unsigned long flags;
  33         long save_sp, save_vbr;
  34         long tmp_vectors[3];
  35 
  36         local_irq_save(flags);
  37         __asm__ __volatile__ (
  38                 "movec %/vbr,%2\n\t"
  39                 "movel #Lberr1,%4@(8)\n\t"
  40                 "movec %4,%/vbr\n\t"
  41                 "movel %/sp,%1\n\t"
  42                 "moveq #0,%0\n\t"
  43                 "tstb %3@\n\t"
  44                 "nop\n\t"
  45                 "moveq #1,%0\n"
  46         "Lberr1:\n\t"
  47                 "movel %1,%/sp\n\t"
  48                 "movec %2,%/vbr"
  49                 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
  50                 : "a" (regp), "a" (tmp_vectors)
  51         );
  52         local_irq_restore(flags);
  53 
  54         return ret;
  55 }
  56 EXPORT_SYMBOL(hwreg_present);
  57 
  58 /* Basically the same, but writes a value into a word register, protected
  59  * by a bus error handler. Returns 1 if successful, 0 otherwise.
  60  */
  61 
  62 int hwreg_write(volatile void *regp, unsigned short val)
  63 {
  64         int ret;
  65         unsigned long flags;
  66         long save_sp, save_vbr;
  67         long tmp_vectors[3];
  68 
  69         local_irq_save(flags);
  70         __asm__ __volatile__ (
  71                 "movec %/vbr,%2\n\t"
  72                 "movel #Lberr2,%4@(8)\n\t"
  73                 "movec %4,%/vbr\n\t"
  74                 "movel %/sp,%1\n\t"
  75                 "moveq #0,%0\n\t"
  76                 "movew %5,%3@\n\t"
  77                 "nop\n\t"
  78                 /*
  79                  * If this nop isn't present, 'ret' may already be loaded
  80                  * with 1 at the time the bus error happens!
  81                  */
  82                 "moveq #1,%0\n"
  83         "Lberr2:\n\t"
  84                 "movel %1,%/sp\n\t"
  85                 "movec %2,%/vbr"
  86                 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
  87                 : "a" (regp), "a" (tmp_vectors), "g" (val)
  88         );
  89         local_irq_restore(flags);
  90 
  91         return ret;
  92 }
  93 EXPORT_SYMBOL(hwreg_write);
  94 

/* [<][>][^][v][top][bottom][index][help] */