NT4/private/ntos/fw/mips/duosync.c
2020-09-30 17:12:29 +02:00

517 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifdef DUO
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
duosync.c
Abstract:
This module contains the routines that perform synchronization
among processors.
Author:
Lluis Abello (lluis) 06-Apr-1993
Environment:
Revision History:
--*/
#include "fwp.h"
#include "iodevice.h"
#include "led.h"
#include "selfmap.h"
#include "selftest.h"
#include "ioaccess.h"
#include "fwstring.h"
volatile PROCESSOR_B_TASK_VECTOR ProcessorBTask;
extern BOOLEAN ProcessorBEnabled;
VOID
InitializePCR(
);
MEMORY_TEST_DATA BMemTest1 = {
0xA0100000,
0x100000,
0,
LED_B_MEMORY_TEST_1
};
MEMORY_TEST_DATA BMemTest2 = {
0x80200000,
0x100000,
0,
LED_B_MEMORY_TEST_2
};
MEMORY_TEST_DATA BMemTest3 = {
VIDEO_MEMORY_VIRTUAL_BASE+1280*1024, // start adr = end of visible screen
0x200000-1280*1024, // size = rest of video memory.
0,
LED_VIDEOMEM
};
//
// The following table defines the selftest routines that will be executed
// by processor B.
//
PROCESSOR_B_TEST ProcessorBSelfTests[] = {
{ProcessorBMemoryTest,&BMemTest1},
{ProcessorBMemoryTest,&BMemTest2},
{ProcessorBVideoMemoryTest,&BMemTest3},
{NULL,0}
};
ULONG
ExecuteOnProcessorB(
IN PPROCESSOR_TASK_ROUTINE Routine,
IN PVOID Data
)
/*++
Routine Description:
This routine puts the supplied Routine and Data in processor B task vector
and issues an IP interrupt to processor B which will then execute
it and set the return value.
Arguments:
None
Return Value:
None
--*/
{
PPROCESSOR_B_TASK_VECTOR TaskVector;
if (!ProcessorBEnabled) {
return 0;
}
//
// Get a non pointer to the Task Vector
//
TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
TaskVector->Routine = Routine;
TaskVector->Data = Data;
//
// Issue an IP interrupt to notify processor B that a task has
// been scheduled for execution.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
//
// If timeout or Return Value indicates error, stop here.
//
if (WaitForIpInterrupt(5000) == FALSE) {
FwPrint("\r\nTimeout waiting for B to execute %lx\r\n",Routine);
}
return (TaskVector->ReturnValue);
}
VOID
ProcessorBMain(
)
/*++
Routine Description:
This is the main routine for processor B.
It jumps here after initialization.
The startup sequence is as follows:
ProcessorA sets the address of this routine in the ProcessorBTask vector.
ProcessorA Enables Processor B in the Global Configuration register.
ProcessorA Calls WaitForIPInterrupt.
When Processor B is enabled it runs at the PROM reset vector, it
initializes itself and jumps to the routine pointed to by ProcessorTask
which is this routine.
Once here processor B Wakes up processor A by issuing an IP interrupt
and Loops for ever waiting for IP interrupts and executing the Task
pointed to by ProcessorBTask.
Arguments:
None
Return Value:
None
--*/
{
PPROCESSOR_TASK_ROUTINE Task;
PVOID TaskData;
ULONG ReturnValue;
//
// Get a pointer to the Task Vector
//
PPROCESSOR_B_TASK_VECTOR TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
//
// Enable IP interrupts.
// All interrupts are disabled in the psr.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptEnable.Long,ENABLE_IP_INTERRUPTS);
for (;;) {
//
// Wake up processor A
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,1);
WaitForIpInterrupt(0);
//
// Execute Task
//
Task = TaskVector->Routine;
TaskData = TaskVector->Data;
ReturnValue = Task(TaskData);
TaskVector->ReturnValue = ReturnValue;
}
}
ULONG
ProcessorBMemoryTest(
IN PMEMORY_TEST_DATA MemoryData
)
/*++
Routine Description:
This routine tests the portion of memory supplied by Data.
Arguments:
MemoryData - Pointer to a data structure describing the range of
memory to be tested.
Return Value:
None
--*/
{
PutLedDisplay(MemoryData->LedDisplayValue);
WriteMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size,MemoryData->XorPattern);
CheckMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size,MemoryData->XorPattern,MemoryData->LedDisplayValue);
return 1;
}
ULONG
ProcessorBVideoMemoryTest(
IN PMEMORY_TEST_DATA MemoryData
)
/*++
Routine Description:
This routine tests the portion of video memory supplied by Data.
Arguments:
MemoryData - Pointer to a data structure describing the range of
memory to be tested.
Return Value:
None
--*/
{
PutLedDisplay(MemoryData->LedDisplayValue);
WriteVideoMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size);
CheckVideoMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size);
return 1;
}
ULONG
CoherencyTest(
IN PVOID CoherentPage
)
/*++
Routine Description:
This routine performs a coherency test. This routine will be executed
simultaneously by both processors.
Processor A stores even bytes and Processor B stores the odd bytes.
To make sure that cache blocks are passed back and forth, a semaphore
locks it's access so that the cache line ping pongs from processor to
processor.
Arguments:
CoherentPage. Pointer aligned to a page boundary. Which is marked
either Exclusive or Shared in the TLB.
The first ulong is used as the semaphore. The rest of the page
is used as data.
Return Value:
Number of errors found.
--*/
{
volatile PULONG Semaphore = (PULONG)CoherentPage;
PULONG CoherentData = Semaphore+64/sizeof(ULONG);
ULONG Counter;
ULONG Processor;
ULONG DataLong;
ULONG Errors = 0;
if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
//
// Processor B
//
Processor = 1;
DataLong = 0xB0B00000;
} else {
Processor = 0;
DataLong = 0xA0A00000;
}
for (Counter = 0; Counter < (0x1000-64)/sizeof(ULONG); Counter += 2) {
//
// Wait for counter.
// No need for interlocks since each processor waits
// for a different value.
//
while (*Semaphore != Counter+Processor) {
}
*(CoherentData+Processor) = DataLong | Counter;
*Semaphore = Counter+Processor+1;
CoherentData += 2;
}
//
// Both processors check all the data.
//
CoherentData = Semaphore+64/sizeof(ULONG);;
for (Counter = 0; Counter < (0x1000-64)/sizeof(ULONG); Counter +=2) {
if (*CoherentData != (Counter | 0xA0A00000)) {
Errors++;
}
CoherentData++;
if (*CoherentData != (Counter | 0xB0B00000)) {
Errors++;
}
CoherentData++;
}
return Errors;
}
BOOLEAN
ProcessorBSelftest(
IN VOID
)
/*++
Routine Description:
This routine sets the different tasks to be executed by processor
b and waits for them to complete. This routine is executed by the
master processor.
Arguments:
None.
Return Value:
TRUE if passed FALSE otherwise
--*/
{
BOOLEAN ReturnValue;
BOOLEAN Timeout;
//
// Get a pointer to the Task Vector
//
PPROCESSOR_B_TASK_VECTOR TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
PPROCESSOR_B_TEST ProcessorBTestList = ProcessorBSelfTests;
//
// Place each task of the SelftestTable in the TaskVector to be executed
// by processor B.
//
while (ProcessorBTestList->Routine != NULL) {
TaskVector->Routine = ProcessorBTestList->Routine;
TaskVector->Data = ProcessorBTestList->Data;
//
// Issue an IP interrupt to notify processor B that a task has
// been scheduled for execution.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
//
// If timeout or Return Value indicates error, stop here.
//
if (((Timeout = WaitForIpInterrupt(5000)) == FALSE) || (TaskVector->ReturnValue == FALSE)) {
if (!Timeout) {
FwPrint("\r\n Wait for Processor B timeout occurred");
} else {
FwPrint("\r\n Processor B failed a test");
}
FwPrint(" Failed test = %08lx\r\n", (ULONG)ProcessorBTestList->Routine);
//return FALSE;
}
//
// Next test.
//
ProcessorBTestList++;
}
//
// Now perform two CoherencyTest
//
FwPrint("\r\n Coherency Test.");
ReturnValue = TRUE;
//
// Zero the page. Set the Task and notify processor B.
// And execute the test simultaneously.
//
RtlZeroMemory((PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE,0x1000);
FwFlushAllCaches();
TaskVector->Routine = CoherencyTest;
TaskVector->Data = (PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE;
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
if (CoherencyTest((PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE) != 0) {
FwPrint(" Processor A Failed.");
ReturnValue = FALSE;
} else {
FwPrint("...");
}
//
// Get and display results from B
//
WaitForIpInterrupt(1000);
if (TaskVector->ReturnValue != 0) {
FwPrint(" Processor B Failed.");
ReturnValue = FALSE;
} else {
FwPrint("...");
}
//
// Do the same with a shared page
//
RtlZeroMemory((PVOID)SHARED_PAGE_VIRTUAL_BASE,0x1000);
FwFlushAllCaches();
TaskVector->Routine = CoherencyTest;
TaskVector->Data = (PVOID)SHARED_PAGE_VIRTUAL_BASE;
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
if (CoherencyTest((PVOID)SHARED_PAGE_VIRTUAL_BASE) != 0) {
FwPrint(" Processor A Failed.");
ReturnValue = FALSE;
} else {
FwPrint("...");
}
WaitForIpInterrupt(1000);
if (TaskVector->ReturnValue != 0) {
FwPrint(" Processor B Failed.");
ReturnValue = FALSE;
} else {
FwPrint("...");
}
//
// Make processor B initialize its PCR
//
TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)InitializePCR;
TaskVector->Data = 0;
//
// Issue an IP interrupt to notify processor B that a task has
// been scheduled for execution.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
//
// If timeout or Return Value indicates error, stop here.
//
if (WaitForIpInterrupt(5000) == FALSE) {
// FwPrint("\r\n Wait for Processor B timeout occurred in init PCR\r\n");
return FALSE;
}
//
// Make processor B cleanup it's caches.
//
TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)HalSweepDcache;
TaskVector->Data = 0;
//
// Issue an IP interrupt to notify processor B that a task has
// been scheduled for execution.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
//
// If timeout or Return Value indicates error, stop here.
//
if (WaitForIpInterrupt(5000) == FALSE) {
// FwPrint("\r\n Wait for Processor B timeout occurred Hal sweep d cachew\r\n");
return FALSE;
}
FwPrint(FW_OK_MSG);
return ReturnValue;
}
#endif // DUO