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