Commit 8738a75f authored by Franksen, Benjamin's avatar Franksen, Benjamin
Browse files

cleanup the code and comments to increase readability


Incidentally, it appears that these changes also make the code work with the
mvme5500 (using RTEMS-4.10 and beatnik BSP).
parent 133bffc6
......@@ -4,7 +4,7 @@
*
* Descr.: test and set a VME byte addr
*
* Author(s): Dan Eichel
* Author(s): Dan Eichel, cleanup by Ben Franksen
*
* Copyright (c) 2010 by Berliner Elektronenspeicherring-Gesellschaft
* fuer Synchrotronstrahlung m.b.H.,
......@@ -12,93 +12,76 @@
*
*********************************************************************-*/
/*----------------------------------------------------*/
/* History */
/*----------------------------------------------------*/
/*
Version 1.0:
testest only for MVME2100 boards. The BSP for the MVME5500 CPUs
seems to be buggy, so that no RTEMS Application can be executed
on such IOCs. Different RTEMS versions from 4.9.0 until 4.9.4 with
several BSP patches were tried, but none worked, so the behavior on
this kind of IOCs is untested! (Date 2010-11-11)
*/
/*----------------------------------------------------*/
/* General Comments */
/*----------------------------------------------------*/
/*
The ppc handles data as big endian but all pci memory mapped registers / IO
space are handled as little endian. So we have to reverse the byte order for
accessing such memory parts.
bosi_test_and_set - test and set a location across the VMEbus utilizing RMW
This routine performs a test-and-set (TAS) instruction on the specified
address, which must be on a different VME board. This function emulates the
TAS function known from the mc68000 processors. For compatibility with the old
motorola CPUs only the highest bit in the adressed byte will be affected.
Unfortunally in this special mode the Universe II can only access adresses
they are four byte aligned, so we have to program the 32bit mask register
to access the right byte. (cf. Universe II User Manual, Chapter 3.4.5.1
Read-Modify-Write, Page 79 for detailed description)
NOTE: bosi_test_and_set can only test-and-set locations across the VMEbus,
local addresses may be tested but never set.
RETURNS: TRUE if the value had not been set but is now
FALSE if the value was already set. */
#include <rtems.h> /* rtems_interrupt_disable */
#include <stdio.h> /* FILE * */
#include <bsp/vmeUniverse.h> /* register offsets and constants */
#include <bsp.h> /* PCI_DRAM_OFFSET */
#include <rtems.h> /* rtems_interrupt_disable */
#include <stdio.h> /* FILE is used in vmeUniverse.h */
#include <bsp/vmeUniverse.h> /* register offsets and constants */
#include <bsp.h> /* PCI_DRAM_OFFSET */
#include "VMEtas.h"
/* register offsets in bsp/vmeUniverse.h are measured in bytes, not words;
this macro encapsulated the necessary shifting and the type casts */
#define out_univ_reg(reg, val)\
out_le32((volatile unsigned *)vmeUniverse0BaseAddr + (reg >> 2), val)
/* next word aligned address below or equal to addr */
#define align(addr)\
((unsigned)(addr) & ~0x3)
/* offset of addr relative to the address of the aligned word that contains it */
#define unaligned_by(addr)\
((unsigned)(addr) - align(addr))
/*
* This routine performs a test-and-set (TAS) on the specified address, which
* must be on a (different) VME board. This emulates the TAS instruction known
* from the mc68000 processors. For compatibility with the old motorola CPUs
* only the highest bit in the adressed byte will be affected.
*
* The implementation uses the ability of the Universe II chip to perform an
* atomic Read-Modify-Write cycle on the VME bus. This special mode of the
* Universe II must be programmed only using word (4 byte) aligned addresses,
* which means we must shift the enable mask and the desired value to be
* swapped back so that they are relative to the next lower (or equal) word
* aligned address (cf. Universe II User Manual, Chapter 3.4.5.1
* Read-Modify-Write, Page 79 for detailed description).
*
* RETURNS: TRUE if the value had not been set but is now
* FALSE if the value was already set.
*/
int VMEtas(unsigned char *addr)
{
int state;
/* value to write back if not set */
unsigned char value = (1<<7);
rtems_interrupt_level level;
/* due to the four byte alignment, the position of the target byte may vary */
/* with respect to the ppc endianness the mask's byte order is reversed */
unsigned long mask = 0x80000000 >> ((unsigned long) addr & 0x3) * 8;
unsigned long register dummy;
unsigned addr_offset = unaligned_by(addr);
unsigned swap = (unsigned)value << 8 * addr_offset;
unsigned mask = swap;
/* Lock interrupts so that issuing RMW are atomic */
rtems_interrupt_disable(level);
*(unsigned long *) ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_EN) = mask;
*(unsigned long *) ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_CMP) = 0x0;
*(unsigned long *) ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_SWP) = 0x80808080;
/* Convert RMW address into the PCI address space and write it into
the UniverseII's UNIV_REGOFF_SCYC_ADDR register with respect
of the PPCs endianness */
__asm__ volatile ("stwbrx %1,0,%2"
: "=r" (dummy)
: "r" ((unsigned long) addr + PCI_DRAM_OFFSET),
"r" ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_ADDR)
);
/* generate a RMW cycle, triggerd be the next read access on addr */
*(unsigned long *) ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_CTL) =
UNIV_SCYC_CTL_SCYC_RMW << 24;
/* set up the universe II chip so that the next read from addr
triggers an atomic RMW cycle */
/* perform RMW to try and set TAS location */
state = *addr;
__asm__ volatile ("sync");
*(unsigned long *) ((unsigned long) vmeUniverse0BaseAddr + UNIV_REGOFF_SCYC_CTL) = 0; /* Disable RMW cycle */
/* enable special cycle for the bits in mask */
out_univ_reg(UNIV_REGOFF_SCYC_EN, mask);
/* when doing the special cycle, compare with zero */
out_univ_reg(UNIV_REGOFF_SCYC_CMP, 0);
/* set the value to be swapped back if comparison succeeds */
out_univ_reg(UNIV_REGOFF_SCYC_SWP, swap);
/* set the address that triggers the RMW cycle */
out_univ_reg(UNIV_REGOFF_SCYC_ADDR, align(addr + PCI_DRAM_OFFSET));
/* program the universe chip to do a RMW cycle */
out_univ_reg(UNIV_REGOFF_SCYC_CTL, UNIV_SCYC_CTL_SCYC_RMW);
/* trigger the RMW by reading from addr */
state = in_8(addr);
/* disable RMW cycle */
out_univ_reg(UNIV_REGOFF_SCYC_CTL, 0);
rtems_interrupt_enable(level);
/* return TAS test result */
return (state & 0x80) ? (0) : (1);
return !(state & value);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment