linux/arch/m68k/mm/hwtest.c
<<
>>
Prefs
   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
  29int 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}
  56EXPORT_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
  62int 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}
  93EXPORT_SYMBOL(hwreg_write);
  94
  95