// SPDX-License-Identifier: GPL-2.01/* Tests for presence or absence of hardware registers.2* This code was originally in atari/config.c, but I noticed3* that it was also in drivers/nubus/nubus.c and I wanted to4* use it in hp300/config.c, so it seemed sensible to pull it5* out into its own file.6*7* The test is for use when trying to read a hardware register8* that isn't present would cause a bus error. We set up a9* temporary handler so that this doesn't kill the kernel.10*11* There is a test-by-reading and a test-by-writing; I present12* them here complete with the comments from the original atari13* config.c...14* -- PMM <[email protected]>, 05/199815*/1617/* This function tests for the presence of an address, specially a18* hardware register address. It is called very early in the kernel19* initialization process, when the VBR register isn't set up yet. On20* an Atari, it still points to address 0, which is unmapped. So a bus21* error would cause another bus error while fetching the exception22* vector, and the CPU would do nothing at all. So we needed to set up23* a temporary VBR and a vector table for the duration of the test.24*/2526#include <linux/module.h>2728#include <asm/hwtest.h>2930int hwreg_present(volatile void *regp)31{32int ret = 0;33unsigned long flags;34long save_sp, save_vbr;35long tmp_vectors[3];3637local_irq_save(flags);38__asm__ __volatile__ (39"movec %/vbr,%2\n\t"40"movel #Lberr1,%4@(8)\n\t"41"movec %4,%/vbr\n\t"42"movel %/sp,%1\n\t"43"moveq #0,%0\n\t"44"tstb %3@\n\t"45"nop\n\t"46"moveq #1,%0\n"47"Lberr1:\n\t"48"movel %1,%/sp\n\t"49"movec %2,%/vbr"50: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)51: "a" (regp), "a" (tmp_vectors)52);53local_irq_restore(flags);5455return ret;56}57EXPORT_SYMBOL(hwreg_present);5859/* Basically the same, but writes a value into a word register, protected60* by a bus error handler. Returns 1 if successful, 0 otherwise.61*/6263int hwreg_write(volatile void *regp, unsigned short val)64{65int ret;66unsigned long flags;67long save_sp, save_vbr;68long tmp_vectors[3];6970local_irq_save(flags);71__asm__ __volatile__ (72"movec %/vbr,%2\n\t"73"movel #Lberr2,%4@(8)\n\t"74"movec %4,%/vbr\n\t"75"movel %/sp,%1\n\t"76"moveq #0,%0\n\t"77"movew %5,%3@\n\t"78"nop\n\t"79/*80* If this nop isn't present, 'ret' may already be loaded81* with 1 at the time the bus error happens!82*/83"moveq #1,%0\n"84"Lberr2:\n\t"85"movel %1,%/sp\n\t"86"movec %2,%/vbr"87: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)88: "a" (regp), "a" (tmp_vectors), "g" (val)89);90local_irq_restore(flags);9192return ret;93}94EXPORT_SYMBOL(hwreg_write);95969798