Mercurial > ecos-v3_0-branch
changeset 84:489eb5632bc3 ecos-sw-2000-04-28
Merge from eCos master repository on 2000-04-28-18:44:39-BST
line wrap: on
line diff
--- a/host/libcdl/ChangeLog +++ b/host/libcdl/ChangeLog @@ -1,3 +1,9 @@ +2000-04-14 Bart Veer <bartv@redhat.com> + + * infer.cxx (infer_set_valuable_value): + Extend the == operator inference support to cope with bool and + booldata options. + 2000-04-11 Bart Veer <bartv@redhat.com> * infer.cxx (infer_make_active):
--- a/host/libcdl/infer.cxx +++ b/host/libcdl/infer.cxx @@ -328,15 +328,55 @@ infer_set_valuable_value(CdlTransaction const CdlValue& current_value = transaction->get_whole_value(valuable); CdlValueFlavor flavor = current_value.get_flavor(); + bool bool_goal = goal.get_bool_value(); - // For now only deal with data items. Interpreter a simple value - // so that it is relevant for booleans etc. can come later. - if (CdlValueFlavor_Data == flavor) { + switch(flavor) { + default : + case CdlValueFlavor_None : + break; + + case CdlValueFlavor_Bool : + if (bool_goal == current_value.is_enabled()) { + result = true; + } else { + if (valuable->is_modifiable() && + (0 == dynamic_cast<CdlLoadable>(valuable)) && + !transaction->changed_by_user(valuable)) { + + valuable->set_enabled(transaction, bool_goal, CdlValueSource_Inferred); + valuable->set_source(transaction, CdlValueSource_Inferred); + result = transaction->resolve_recursion(level); + } + + } + break; + + case CdlValueFlavor_BoolData : + if (!bool_goal && !current_value.is_enabled()) { + result = true; + } else if (bool_goal && current_value.is_enabled() && (goal == current_value.get_simple_value())) { + result = true; + } else { + if (valuable->is_modifiable() && + (0 == dynamic_cast<CdlLoadable>(valuable)) && + !transaction->changed_by_user(valuable)) { + + if (!bool_goal) { + valuable->disable(transaction, CdlValueSource_Inferred); + } else { + valuable->enable_and_set_value(transaction, goal, CdlValueSource_Inferred); + } + valuable->set_source(transaction, CdlValueSource_Inferred); + result = transaction->resolve_recursion(level); + } + } + break; + + case CdlValueFlavor_Data: // Now check whether or not the valuable already has the desired value if (goal == current_value.get_simple_value()) { result = true; } else { - if (valuable->is_modifiable() && (0 == dynamic_cast<CdlLoadable>(valuable)) && !transaction->changed_by_user(valuable)) { @@ -347,6 +387,7 @@ infer_set_valuable_value(CdlTransaction result = transaction->resolve_recursion(level); } } + break; } CYG_REPORT_RETVAL(result);
--- a/host/tools/Utils/ChangeLog +++ b/host/tools/Utils/ChangeLog @@ -1,3 +1,9 @@ +2000-04-14 Simon FitzMaurice <sdf@redhat.co.uk> + * common\Subprocess.cpp + common\Subprocess.h + + Always attempt to kill a process explicitly (don't let Cygwin processes linger) + 2000-04-13 Simon FitzMaurice <sdf@redhat.co.uk> * common\eCosSerial.cpp common\eCosSocket.cpp
--- a/host/tools/Utils/common/Subprocess.cpp +++ b/host/tools/Utils/common/Subprocess.cpp @@ -68,9 +68,9 @@ CSubprocess::CSubprocess(bool bAutoDelet m_pfnLogfunc(0), m_bKillThread(false) { - #ifdef _WIN32 - InitializeCriticalSection(&m_cs); - #endif +#ifdef _WIN32 + m_hProcess=0; +#endif } CSubprocess::~CSubprocess() @@ -80,9 +80,11 @@ CSubprocess::~CSubprocess() m_bKillThread=true; CeCosThreadUtils::WaitFor(m_bThreadTerminated); } - #ifdef _WIN32 - DeleteCriticalSection(&m_cs); - #endif +#ifdef _WIN32 + if(m_hProcess){ + CloseHandle(m_hProcess); + } +#endif } bool CSubprocess::Run(LogFunc *pfnLog,void * pLogparam, LPCTSTR pszCmd,bool bBlock/*=true*/) @@ -96,6 +98,10 @@ bool CSubprocess::Run(LogFunc *pfnLog,vo #ifdef _WIN32 // UNIX does it from the thread func. WIN32 could too, but it's nice to know at the time // of calling run whether the process is successfully created. + if(m_hProcess){ + // Normally done in the dtor + CloseHandle(m_hProcess); + } rc=CreateProcess(pszCmd); #else m_strCmd=pszCmd; @@ -224,7 +230,7 @@ bool CSubprocess::CreateProcess(LPCTSTR if(m_bVerbose){ Output(String::SFormat(_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline)); } - TRACE(String::SFormat(_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline)); + TRACE(String::SFormat(_T("Process %d created \"%s\"\n"),m_idProcess,pszCmdline)); m_nExitCode=STILL_ACTIVE; CloseHandle(pi.hThread); } else { @@ -232,7 +238,7 @@ bool CSubprocess::CreateProcess(LPCTSTR if(m_bVerbose){ Output(String::SFormat(_T("*** Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString())); } - TRACE(String::SFormat(_T("*** Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString())); + TRACE(String::SFormat(_T("Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString())); m_nExitCode=GetLastError(); CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE; CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE; @@ -301,10 +307,6 @@ void CSubprocess::ThreadFunc() CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE; CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE; - EnterCriticalSection(&m_cs); - CloseHandle(m_hProcess); - m_hProcess=0; // Do not use INVALID_HANDLE_VALUE, which is also the pseudo-handle returned by GetCurrentProcess() - LeaveCriticalSection(&m_cs); if(m_bAutoDelete){ m_bThreadTerminated=true; // or else the dtor will block @@ -496,13 +498,12 @@ TRACE(_T("CSubprocess::Kill pid %d recur #ifdef _WIN32 - EnterCriticalSection(&m_cs); // because the thread func may be closing it if(m_hProcess){ - TRACE(_T("Terminate m_idProcess %d [%s]\n"),m_idProcess,(LPCTSTR)Name(m_idProcess)); + TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(m_idProcess)); rc=(TRUE==::TerminateProcess(m_hProcess,PROCESS_KILL_EXIT_CODE)); - // Threadfunc's responsibility alone to close the handle + // dtor's (or subsequent Run's) responsibility to close the handle } - LeaveCriticalSection(&m_cs); + #else rc=(0==kill(m_idProcess,SIGTERM)); int status; @@ -524,8 +525,7 @@ TRACE(_T("CSubprocess::Kill pid %d recur // end hack HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID); if(hProcess){ - TRACE(_T("Terminate m_idProcess %d [%s]\n"),arPinfo[i].PID,(LPCTSTR)Name(arPinfo[i].PID)); - + TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(arPinfo[i].PID)); rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE)); CloseHandle(hProcess); } else { @@ -550,12 +550,10 @@ Time CSubprocess::CpuTime(bool bRecurse) // FIXME: needs to be top-down #ifdef _WIN32 - EnterCriticalSection(&m_cs); // because the thread func may be closing it __int64 ftCreation,ftExit,ftKernel,ftUser; if(m_hProcess && ::GetProcessTimes (m_hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){ t+=Time((ftKernel+ftUser)/10000); } - LeaveCriticalSection(&m_cs); if(bRecurse){ PInfoArray arPinfo; @@ -689,12 +687,6 @@ bool CSubprocess::PSExtract(CSubprocess: SetParents(arPinfo); -/* -for(int k=0;k<(signed)arPinfo.size();k++){ - const PInfo &p=arPinfo[k]; - TRACE(_T("%d%c pid=%4d ppid=%4d t=%I64d [%s]\n"),k,p.IsChildOf(GetCurrentProcessId())?_TCHAR('*'):_TCHAR(':'),p.PID,p.PPID,p.t,(LPCTSTR)Name(p.PID)); -} -*/ if(!rc){ ERROR(_T("Couldn't get process information!\n")); } @@ -780,7 +772,7 @@ void CSubprocess::SetParents(CSubprocess ERROR(_T("!!! Circularly linked process list at index %d\n"),i); for(int k=0;k<(signed)arPinfo.size();k++){ const PInfo &p=arPinfo[k]; - ERROR(_T("%d: pid=%4d ppid=%4d [%s]\n"),k,p.PID,p.PPID,(LPCTSTR)Name(p.PID)); + ERROR(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID); } } } @@ -797,7 +789,7 @@ bool CSubprocess::PInfo::IsChildOf(int p const String CSubprocess::Name(int pid) { - String str; + String str(String::SFormat(_T("id=%d"),pid)); #ifdef _DEBUG #ifdef _WIN32 if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){ @@ -812,9 +804,10 @@ const String CSubprocess::Name(int pid) DWORD dwSize; if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){ // Get Full pathname: - LPTSTR buf=str.GetBuffer(MAX_PATH); + TCHAR buf[1+MAX_PATH]; lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH); - str.ReleaseBuffer(); + str+=_TCHAR(' '); + str+=buf; } CloseHandle(hProcess); }
--- a/host/tools/Utils/common/Subprocess.h +++ b/host/tools/Utils/common/Subprocess.h @@ -146,7 +146,6 @@ protected: HANDLE m_hrPipe; HANDLE m_hwPipe; HANDLE m_hProcess; // This handle is "owned" by the ThreadFunc - mutable CRITICAL_SECTION m_cs; // protects m_hProcess static HINSTANCE hInstLib1, hInstLib2; int m_nErr; #else
--- a/host/tools/configtool/ChangeLog +++ b/host/tools/configtool/ChangeLog @@ -1,3 +1,17 @@ +2000-04-17 John Dallaway <jld@cygnus.co.uk> + + * standalone/common/cdl_exec.cxx: + + Use PATH_MAX rather than _MAX_PATH in the Cygwin-hosted + build. + +2000-04-17 John Dallaway <jld@cygnus.co.uk> + + * standalone/common/cdl_exec.cxx: + + Modify cmd_tree() to avoid non-standard use of + getcwd(). + 2000-04-11 John Dallaway <jld@cygnus.co.uk> * common/win32/CTCommonDoc.cpp:
--- a/host/tools/configtool/standalone/common/cdl_exec.cxx +++ b/host/tools/configtool/standalone/common/cdl_exec.cxx @@ -244,7 +244,12 @@ bool cdl_exec::cmd_tree () { pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); interp = CdlInterpreterBody::make (); config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - char * cwd = getcwd (NULL, 0); +#ifdef _MSC_VER + char cwd [_MAX_PATH + 1]; +#else + char cwd [PATH_MAX + 1]; +#endif + getcwd (cwd, sizeof cwd); #ifdef __CYGWIN__ char cwd_win32 [MAXPATHLEN + 1]; cygwin_conv_to_win32_path (cwd, cwd_win32); @@ -252,7 +257,6 @@ bool cdl_exec::cmd_tree () { #else generate_build_tree (config, cwd, install_prefix); #endif - free (cwd); config->generate_config_headers (install_prefix.empty () ? "install/include/pkgconf" : install_prefix + "/include/pkgconf"); status = true; } catch (CdlStringException exception) {
--- a/host/tools/ecostest/ChangeLog +++ b/host/tools/ecostest/ChangeLog @@ -1,3 +1,7 @@ +2000-04-14 Simon FitzMaurice <sdf@redhat.co.uk> + * common\ResetAttributes.cpp : do not carry forward values for skipped fields in reset strings + * common\eCosTest.cpp : Avoid overflow in socket timeouts + 2000-04-13 Jesper Skov <jskov@redhat.com> * unix/Makefile: add randfile
--- a/host/tools/ecostest/common/ResetAttributes.cpp +++ b/host/tools/ecostest/common/ResetAttributes.cpp @@ -340,13 +340,13 @@ CResetAttributes::ResetResult CResetAttr // 2. Read timeout StringArray ar; int nArgs=strArg.Chop(ar,ARGSEP,true); - if(nArgs>0 && ar[0].size()){ + if(nArgs>0){ m_strAuxPort=ar[0]; } - if(nArgs>1 && ar[1].size()){ + if(nArgs>1){ m_nBaud=_ttoi(ar[1]); } - if(nArgs>2 && ar[2].size()){ + if(nArgs>2){ m_nReadTimeout=_ttoi(ar[2]); } } else if (_T("off")==strID || _T("on")==strID || _T("on_off")==strID || _T("off_on")==strID) { @@ -360,22 +360,22 @@ CResetAttributes::ResetResult CResetAttr // 5. Delay StringArray ar; int nArgs=strArg.Chop(ar,ARGSEP,true); - if(nArgs>0 && ar[0].size()){ + if(nArgs>0){ m_strHostPort=ar[0]; } - if(nArgs>1 && ar[1].size()){ + if(nArgs>1){ m_strControl=ar[1]; } - if(nArgs>2 && ar[2].size()){ + if(nArgs>2){ m_strAuxPort=ar[2]; } - if(nArgs>3 && ar[3].size()){ + if(nArgs>3){ m_nBaud=_ttoi(ar[3]); } - if(nArgs>4 && ar[4].size()){ + if(nArgs>4){ m_nReadTimeout=_ttoi(ar[4]); } - if(nArgs>5 && ar[5].size()){ + if(nArgs>5){ m_nDelay=_ttoi(ar[5]); }
--- a/host/tools/ecostest/common/eCosTest.cpp +++ b/host/tools/ecostest/common/eCosTest.cpp @@ -926,6 +926,7 @@ void CeCosTest::AcceptThreadFunc() sendResult(); m_pSock->recvInteger(n); // receive an ack } else { + // Client-side GDB bool bTargetReady; if(_TCHAR('\0')==*(m_pResource->ResetString())){ bTargetReady=true; @@ -938,12 +939,11 @@ void CeCosTest::AcceptThreadFunc() m_pSock->sendInteger(bTargetReady,_T("target ready indicator")); int nAck=-1; - int dTimeout=m_ep.DownloadTimeout()+MAX(3*m_ep.ActiveTimeout(),15*60*1000); if(bTargetReady){ if(CeCosSocket::IsLegalHostPort(m_pResource->Serial())){ TRACE(_T("Sending %s\n"),(LPCTSTR)m_pResource->Serial()); - if(m_pSock->sendString(m_pResource->Serial(),_T("Serial name")) && m_pSock->recvInteger(nAck,_T("Terminating ack"),dTimeout)){ + if(m_pSock->sendString(m_pResource->Serial(),_T("Serial name")) && m_pSock->recvInteger(nAck,_T("Terminating ack"),CeCosSocket::NOTIMEOUT)){ TRACE(_T("Terminating ack=%d\n"),nAck); } } else { @@ -963,7 +963,7 @@ void CeCosTest::AcceptThreadFunc() CeCosThreadUtils::RunThread(SConnectSocketToSerialThreadFunc,this,&bConnectSocketToSerialThreadDone,_T("SConnectSocketToSerialThreadFunc")); // Wait for either client or the ConnectSocketToSerial thread to finish. - if(m_pSock->recv(&nAck,sizeof(int),_T("Terminating ack"),dTimeout,DerefBool,&bConnectSocketToSerialThreadDone)){ + if(m_pSock->recv(&nAck,sizeof(int),_T("Terminating ack"),CeCosSocket::NOTIMEOUT,DerefBool,&bConnectSocketToSerialThreadDone)){ TRACE(_T("Session terminated by request of client (%s)\n"),(LPCTSTR)Image((StatusType)nAck)); } else if(0!=m_pSock->SocketError()){ TRACE(_T("Session terminated by socket error - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
--- a/host/tools/ecostest/common/eCosTestDownloadFilter.cpp +++ b/host/tools/ecostest/common/eCosTestDownloadFilter.cpp @@ -53,7 +53,7 @@ #include "eCosStd.h" #include "eCosTrace.h" -#define DL_FILTER_VER "$Id: eCosTestDownloadFilter.cpp,v 1.4 2000/04/18 21:51:58 jlarmour Exp $" +#define DL_FILTER_VER "$Id: eCosTestDownloadFilter.cpp,v 1.5 2000/04/28 18:18:41 jlarmour Exp $" #include "eCosTestDownloadFilter.h" CeCosTestDownloadFilter::CeCosTestDownloadFilter():
--- a/host/tools/ecostest/common/eCosTestMonitorFilter.cpp +++ b/host/tools/ecostest/common/eCosTestMonitorFilter.cpp @@ -45,7 +45,7 @@ #include "eCosStd.h" -#define SER_FILTER_VER "$Id: eCosTestMonitorFilter.cpp,v 1.3 2000/04/18 21:51:58 jlarmour Exp $" +#define SER_FILTER_VER "$Id: eCosTestMonitorFilter.cpp,v 1.4 2000/04/28 18:18:41 jlarmour Exp $" #include "eCosTestMonitorFilter.h" CeCosTestMonitorFilter::CeCosTestMonitorFilter():
--- a/host/tools/ecostest/common/eCosTestSerialFilter.cpp +++ b/host/tools/ecostest/common/eCosTestSerialFilter.cpp @@ -51,7 +51,7 @@ #include "eCosStd.h" -#define SER_FILTER_VER "$Id: eCosTestSerialFilter.cpp,v 1.4 2000/04/18 21:51:58 jlarmour Exp $" +#define SER_FILTER_VER "$Id: eCosTestSerialFilter.cpp,v 1.5 2000/04/28 18:18:41 jlarmour Exp $" #include "eCosTestSerialFilter.h" #include "eCosThreadUtils.h"
--- a/packages/compat/uitron/current/tests/testintr.cxx +++ b/packages/compat/uitron/current/tests/testintr.cxx @@ -316,6 +316,7 @@ void task1( unsigned int arg ) #endif } + // First test that dis_int() and ena_int() work for the clock interrupt #ifdef CYGSEM_UITRON_BAD_PARAMS_RETURN_ERRORS ercd = ena_int( 123456789 ); // Hope this is large enough to error
--- a/packages/devs/eth/arm/ebsa285/current/ChangeLog +++ b/packages/devs/eth/arm/ebsa285/current/ChangeLog @@ -1,3 +1,38 @@ +2000-04-27 Hugo Tyson <hmt@cygnus.co.uk> + + * src/if_ebsa285.c: A serious re-write. This cuts out a lot of + code from the old version and improves the performance greatly. + + The cruft was mainly doing lots of explicit event communication + between the ISR and DSR, when in fact all the state needed is + present in the tx/rx rings. So both ISRs and DSRs regard their + call as an opportunity to progress everything they can, rather + than only dealing with one interrupt cause at a time; the + connection between them is now rather looser. + + Interrups can now be re-enabled after the ISR (in other words they + are not masked in the ISR), no need to wait for the DSR, but in + consequence some DSR code must mask/unmask intrs as it works. + + The 82559 appears to be a little slow in reacting to commands and + state changes, so some interrupts were being lost - or persisting + beyond their desired life - so there's some kinda polling code to + deal with that also. We also rely on the foreground to kind of + poll in the same way, in the send/can_send calls - we know the + stack will re-try if necessary, though this is rare. + + The driver now works (albeit at much reduced performance) with as + few as 6 rx and tx buffers - in other words the "queue full/out of + rx buffers" states have been tested and all is well. It works + generally fine with 8 buffers of each kind. + + The mux ISR and DSR are now rather more polled than the old + versions; we just try to do things with both devices (if active) + by simply calling each unitary ISR/DSR respectively. + + I also re-ordered some of the code, moving utilities to the end of + the file and grouping together Tx and Rx machines a bit better. + 2000-04-13 Hugo Tyson <hmt@cygnus.co.uk> * src/if_ebsa285.c: Attribution to Ron Spence, Pacific Softworks
--- a/packages/devs/eth/arm/ebsa285/current/src/if_ebsa285.c +++ b/packages/devs/eth/arm/ebsa285/current/src/if_ebsa285.c @@ -142,6 +142,10 @@ static inline cyg_uint32 bus_to_virt(cyg #define SCB_STATUS_SWI 0x0400 // software generated interrupt #define SCB_STATUS_FCP 0x0100 // flow control pause interrupt +#define SCB_INTACK_MASK 0xFD00 // all the above + +#define SCB_INTACK_TX (SCB_STATUS_CX | SCB_STATUS_CNA) +#define SCB_INTACK_RX (SCB_STATUS_FR | SCB_STATUS_RNR) // ------------------------------------------------------------------------ // @@ -202,7 +206,7 @@ static inline cyg_uint32 bus_to_virt(cyg #define CU_RESUME 0x0020 #define CU_STATSADDR 0x0040 // Load Dump Statistics ctrs addr #define CU_SHOWSTATS 0x0050 // Dump statistics counters. -#define CU_CMD_BASE 0x0060 // Base address to add to CU commands +#define CU_ADDR_LOAD 0x0060 // Base address to add to CU commands #define CU_DUMPSTATS 0x0070 // Dump then reset stats counters. // RUC COMMANDS @@ -210,7 +214,7 @@ static inline cyg_uint32 bus_to_virt(cyg #define RUC_START 0x0001 #define RUC_RESUME 0x0002 #define RUC_ABORT 0x0004 -#define RUC_ADDR_LOAD 0x0006 +#define RUC_ADDR_LOAD 0x0006 // (seems not to clear on acceptance) #define RUC_RESUMENR 0x0007 #define SCB_M 0x0100 // 0 = enable interrupt, 1 = disable @@ -219,33 +223,17 @@ static inline cyg_uint32 bus_to_virt(cyg #define CU_STATUS_MASK 0x00C0 #define RU_STATUS_MASK 0x003C -#define CUC_ADDR_LOAD 0x0060 -#define CUC_START 0x0010 - -#define MAX_MEM_RESERVED_IOCTL 1000 - -// We use this as a templete when writing a new MAC address into the -// eeproms. The MAC address in the first few bytes is over written -// with the correct MAC address and then the whole lot is programmed -// into the serial EEPROM. The checksum is calculated on the fly and -// sent instead of the last two bytes. +#define RU_STATUS_IDLE (0<<2) +#define RU_STATUS_SUS (1<<2) +#define RU_STATUS_NORES (2<<2) +#define RU_STATUS_READY (4<<2) +#define RU_STATUS_NO_RBDS_SUS ((1<<2)|(8<<2)) +#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2)) +#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2)) -static char eeprom_burn[126] = { - 0x00, 0x90, 0x27, 0x8c, 0x57, 0x82, 0x03, 0x02, 0x00, 0x00, 0x01, - 0x02, 0x01, 0x47, 0x00, 0x00, 0x13, 0x72, 0x06, 0x83, 0xa2, 0x40, - 0x0c, 0x00, 0x86, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 -}; + - +#define MAX_MEM_RESERVED_IOCTL 1000 // ------------------------------------------------------------------------ // @@ -371,6 +359,7 @@ typedef struct { typedef struct { + cyg_uint32 interrupts; cyg_uint32 rx_count; cyg_uint32 rx_deliver; cyg_uint32 rx_resource; @@ -391,6 +380,14 @@ I82559_COUNTERS i82559_counters[2]; #define MAX_RX_PACKET_SIZE 1536 // maximum Rx packet size #define MAX_TX_PACKET_SIZE 1536 // maximum Tx packet size +// The system seems to work OK with as few as 8 of RX and TX descriptors. +// It limps very painfully with only 4. +// Performance is better with more than 8. +// But the size of non-cached (so useless for anything else) +// memory window is 1Mb, so we might as well use it all. +// +// 128 for these uses the whole 1Mb, near enough. + #ifndef MAX_RX_DESCRIPTORS #define MAX_RX_DESCRIPTORS 128 // number of Rx descriptors #endif @@ -407,8 +404,7 @@ typedef struct i82559 { active:1, // has this if been brung up? spare1:5; cyg_uint8 - out_of_resources:1, // need to restart rx engine. - spare2:7; + spare2:8; cyg_uint8 tx_in_progress:1, // transmit in progress flag tx_queue_full:1, // all Tx descriptors used flag @@ -424,7 +420,9 @@ typedef struct i82559 { RFD *rx_ring[MAX_RX_DESCRIPTORS]; // location of Rx descriptors int tx_descriptor_add; // descriptor index for additions - int tx_descriptor_remove; // descriptor index for removals + int tx_descriptor_active; // descriptor index for active tx + int tx_descriptor_remove; // descriptor index for remove + TxCB *tx_ring[MAX_TX_DESCRIPTORS]; // location of Tx descriptors unsigned long tx_keys[MAX_TX_DESCRIPTORS]; // keys for tx q management @@ -508,31 +506,6 @@ CYG_MACRO_END // ------------------------------------------------------------------------ // -// Communications from ISR to DSR -// -// ------------------------------------------------------------------------ - -#define PACKET_RX 1 -#define PACKET_TX 2 - -typedef struct { - cyg_uint32 request; - void *p; - unsigned long key; -} I82559_QUEUE; - -// 82559 thread request queue -#define I82559_QUEUE_SIZE \ - ((MAX_RX_DESCRIPTORS + MAX_TX_DESCRIPTORS) * MAX_82559) - -I82559_QUEUE i82559_queue[I82559_QUEUE_SIZE]; -int i82559_q_in; // queue insertion index -int i82559_q_out; // queue removal index -int i82559_q_full; // queue full flag - - -// ------------------------------------------------------------------------ -// // Managing the memory that is windowed onto the PCI bus // // ------------------------------------------------------------------------ @@ -556,7 +529,6 @@ static void i82559_reset(struct i82559* static void InitRxRing(struct i82559* p_i82559); static void ResetRxRing(struct i82559* p_i82559); -static void PacketRxReady(struct i82559* p_i82559); static void InitTxRing(struct i82559* p_i82559); static void ResetTxRing(struct i82559* p_i82559); @@ -565,14 +537,24 @@ static void program_eeprom(cyg_uint32 , static int eth_set_promiscuous_mode(struct i82559* p_i82559); +// debugging/logging only: +void dump_txcb(TxCB *p_txcb); +void DisplayStatistics(void); +void dump_rfd(RFD *p_rfd, int anyway ); +void dump_all_rfds( int intf ); +void dump_packet(cyg_uint8 *p_buffer, int length); + // ------------------------------------------------------------------------ -// utility that is used in statistics routine +// utilities // ------------------------------------------------------------------------ + static inline void wait_for_cmd_done(long scb_ioaddr) { - int wait = 10000; - do /* nothing */ ; - while( INB(scb_ioaddr) && --wait >= 0); + register int CSRstatus; + register int wait = 0x100000; + do CSRstatus = INB(scb_ioaddr + SCBCmd) ; + while( CSRstatus && --wait >= 0); + CYG_ASSERT( wait > 0, "wait_for_cmd_done" ); } static inline void Mask82559Interrupt(struct i82559* p_i82559) @@ -587,6 +569,41 @@ static inline void UnMask82559Interrupt( cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_PCI_IRQ); } +#ifdef CYGDBG_USE_ASSERTS // an indication of a debug build +static int acknowledge82559interrupt_compensating = 0; +#endif + +static void Acknowledge82559Interrupt(struct i82559* p_i82559) +{ + int sources, mask; + cyg_uint32 ioaddr; + cyg_uint16 status; + int loops = 64; + + cyg_drv_interrupt_acknowledge(p_i82559->vector); + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_PCI_IRQ); + + // It appears that some time can be taken before the interrupt source + // *really* quietens down... this is ugly, but effective. + // Without it, we get "Spurious Interrupt!" failures. + ioaddr = p_i82559->io_address; // get I/O address for 82559 + mask = (1 << p_i82559->vector); // Do not include the MUX vector or we + sources = *SA110_IRQCONT_IRQSTATUS; //...get hung on the other 82559 + status = INW(ioaddr + SCBStatus); + while ( ((0 != (sources & mask)) || (0 != (status & SCB_INTACK_MASK))) + && --loops >= 0) { + OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus); + cyg_drv_interrupt_acknowledge(p_i82559->vector); + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_PCI_IRQ); +#ifdef CYGDBG_USE_ASSERTS + acknowledge82559interrupt_compensating++; // verify this is executed +#endif + sources = *SA110_IRQCONT_IRQSTATUS; + status = INW(ioaddr + SCBStatus); + } + CYG_ASSERT( loops >= 0, "Acknowledge82559Interrupt" ); +} + static void udelay(int delay) { @@ -599,204 +616,6 @@ static void udelay(int delay) } // ------------------------------------------------------------------------ -// -// -// CODE FOR DEBUGGING PURPOSES ONLY -// -// -// ------------------------------------------------------------------------ -void dump_txcb(TxCB *p_txcb) -{ - os_printf("TxCB @ %x\n", (int)p_txcb); - os_printf("status = %04X ", p_txcb->status); - os_printf("command = %04X ", p_txcb->command); - os_printf("link = %08X ", p_txcb->link); - os_printf("tbd = %08X ", p_txcb->tbd_address); - os_printf("count = %d ", p_txcb->count); - os_printf("eof = %x ", p_txcb->eof); - os_printf("threshold = %d ", p_txcb->tx_threshold); - os_printf("tbd number = %d\n", p_txcb->tbd_number); -} - - -// This is intended to be the body of a THREAD that prints stuff every 10 -// seconds or so: -#ifdef KEEP_STATISTICS -#ifdef DISPLAY_STATISTICS -void DisplayStatistics(void) -{ - int i; - I82559_COUNTERS *p_statistics; - cyg_uint32 *p_counter; - cyg_uint32 *p_register; - int reg_count; - int status; - - while ( 1 ) { -#ifdef DISPLAY_82559_STATISTICS - for ( i = 0; i < 2; i ++ ) { - p_statistics = (I82559_COUNTERS *)i82559[i].p_statistics; - if ( (p_statistics->done & 0xFFFF) == 0xA007 ) { - p_counter = (cyg_uint32 *)&i82559_counters[i]; - p_register = (cyg_uint32 *)&p_statistics->tx_good; - for ( reg_count = 20; reg_count != 0; reg_count--) { - *p_counter += *p_register; - p_counter++; - p_register++; - } - p_statistics->done = 0; - // make sure no command operating - wait_for_cmd_done(i82559[i].io_address + SCBCmd); - // start register dump - OUTW(CU_DUMPSTATS, i82559[i].io_address + SCBCmd); - } - } -#endif - os_printf("\nRx\nPackets = %d %d\n", - statistics[0].rx_count, statistics[1].rx_count); - os_printf("Deliver %d %d\n", - statistics[0].rx_deliver, statistics[1].rx_deliver); - os_printf("Resource %d %d\n", - statistics[0].rx_resource, statistics[1].rx_resource); - os_printf("Restart %d %d\n", - statistics[0].rx_restart, statistics[1].rx_restart); - -#ifdef DISPLAY_82559_STATISTICS - os_printf("Count %d %d\n", - i82559_counters[0].rx_good, i82559_counters[1].rx_good); - os_printf("CRC %d %d\n", - i82559_counters[0].rx_crc_errors, i82559_counters[1].rx_crc_errors); - os_printf("Align %d %d\n", - i82559_counters[0].rx_align_errors, i82559_counters[1].rx_align_errors); - os_printf("Resource %d %d\n", - i82559_counters[0].rx_resource_errors, i82559_counters[1].rx_resource_errors); - os_printf("Overrun %d %d\n", - i82559_counters[0].rx_overrun_errors, i82559_counters[1].rx_overrun_errors); - os_printf("Collision %d %d\n", - i82559_counters[0].rx_collisions, i82559_counters[1].rx_collisions); - os_printf("Short %d %d\n", - i82559_counters[0].rx_short_frames, i82559_counters[1].rx_short_frames); -#endif - os_printf("\nTx\nPackets = %d %d\n", - statistics[0].tx_count, statistics[1].tx_count); - os_printf("Complete %d %d\n", - statistics[0].tx_complete, statistics[1].tx_complete); - os_printf("Dropped %d %d\n", - statistics[0].tx_dropped, statistics[1].tx_dropped); - os_printf("Count %d %d\n", - i82559_counters[0].tx_good, i82559_counters[1].tx_good); -#ifdef DISPLAY_82559_STATISTICS - os_printf("Collision %d %d\n", - i82559_counters[0].tx_max_collisions,i82559_counters[1].tx_max_collisions); - os_printf("Late Col. %d %d\n", - i82559_counters[0].tx_late_collisions,i82559_counters[1].tx_late_collisions); - os_printf("Underrun %d %d\n", - i82559_counters[0].tx_underrun,i82559_counters[1].tx_underrun); - os_printf("Carrier %d %d\n", - i82559_counters[0].tx_carrier_loss,i82559_counters[1].tx_carrier_loss); - os_printf("Deferred %d %d\n", - i82559_counters[0].tx_deferred, i82559_counters[1].tx_deferred); - os_printf("1 Col %d %d\n", - i82559_counters[0].tx_single_collisions, i82559_counters[0].tx_single_collisions); - os_printf("Mult. Col %d %d\n", - i82559_counters[0].tx_mult_collisions, i82559_counters[0].tx_mult_collisions); - os_printf("Total Col %d %d\n", - i82559_counters[0].tx_total_collisions, i82559_counters[0].tx_total_collisions); -#endif - status = INB(i82559[0].io_address + SCBGenStatus); - os_printf("Interface 0 Link = %s, %s Mbps, %s Duplex\n", - status & GEN_STATUS_LINK ? "Up" : "Down", - status & GEN_STATUS_100MBPS ? "100" : "10", - status & GEN_STATUS_FDX ? "Full" : "Half"); - - status = INB(i82559[1].io_address + SCBGenStatus); - os_printf("Interface 1 Link = %s, %s Mbps, %s Duplex\n", - status & GEN_STATUS_LINK ? "Up" : "Down", - status & GEN_STATUS_100MBPS ? "100" : "10", - status & GEN_STATUS_FDX ? "Full" : "Half"); - - cyg_thread_delay(1000); - } -} -#endif // DISPLAY_STATISTICS -#endif // KEEP_STATISTICS - -void dump_rfd(RFD *p_rfd, int anyway ) -{ - if ( (0 != p_rfd->status) || anyway ) { - os_printf("RFD @ %x = ", (int)p_rfd); - os_printf("status = %x ", p_rfd->status); - os_printf("link = %x ", p_rfd->link); -// os_printf("rdb_address = %x ", p_rfd->rdb_address); - os_printf("count = %x ", p_rfd->count); - os_printf("f = %x ", p_rfd->f); - os_printf("eof = %x ", p_rfd->eof); - os_printf("size = %x\n", p_rfd->size); - os_printf("[%04x %04x %04x] ", - *((cyg_uint16 *)(&(p_rfd->buffer[0]))), - *((cyg_uint16 *)(&(p_rfd->buffer[2]))), - *((cyg_uint16 *)(&(p_rfd->buffer[4]))) ); - os_printf("[%04x %04x %04x] %04x : ", - *((cyg_uint16 *)(&(p_rfd->buffer[6]))), - *((cyg_uint16 *)(&(p_rfd->buffer[8]))), - *((cyg_uint16 *)(&(p_rfd->buffer[10]))), - *((cyg_uint16 *)(&(p_rfd->buffer[12]))) ); - os_printf("(%04x %04x %04x %04x) ", - *((cyg_uint16 *)(&(p_rfd->buffer[14]))), - *((cyg_uint16 *)(&(p_rfd->buffer[16]))), - *((cyg_uint16 *)(&(p_rfd->buffer[18]))), - *((cyg_uint16 *)(&(p_rfd->buffer[20]))) ); - os_printf("[%04x %04x %04x] ", - *((cyg_uint16 *)(&(p_rfd->buffer[22]))), - *((cyg_uint16 *)(&(p_rfd->buffer[24]))), - *((cyg_uint16 *)(&(p_rfd->buffer[26]))) ); - os_printf("%d.%d.%d.%d ", - *((cyg_uint8 *)(&(p_rfd->buffer[28]))), - *((cyg_uint8 *)(&(p_rfd->buffer[29]))), - *((cyg_uint8 *)(&(p_rfd->buffer[30]))), - *((cyg_uint8 *)(&(p_rfd->buffer[31]))) ); - os_printf("[%04x %04x %04x] ", - *((cyg_uint16 *)(&(p_rfd->buffer[32]))), - *((cyg_uint16 *)(&(p_rfd->buffer[34]))), - *((cyg_uint16 *)(&(p_rfd->buffer[36]))) ); - os_printf("%d.%d.%d.%d ...\n", - *((cyg_uint8 *)(&(p_rfd->buffer[38]))), - *((cyg_uint8 *)(&(p_rfd->buffer[39]))), - *((cyg_uint8 *)(&(p_rfd->buffer[40]))), - *((cyg_uint8 *)(&(p_rfd->buffer[41]))) ); - } -} - -void dump_all_rfds( int intf ) -{ - struct i82559* p_i82559 = &i82559[intf]; - int i, j; - j = p_i82559->next_rx_descriptor; - os_printf("rx descriptors for interface %d (eth%d):\n", intf, intf ); - for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) - dump_rfd( p_i82559->rx_ring[i], (i > (j-3) && (i <= j)) ); - os_printf("next rx descriptor = %x\n\n", j); -} - - -void dump_packet(cyg_uint8 *p_buffer, int length) -{ - int count; - - count = 0; - while ( length > 0 ) { - if ( count == 0 ) - os_printf("\n"); - count = (count + 1) & 0x0F; - os_printf("%02X ", *p_buffer++); - length--; - } - os_printf("\n"); -} - - - -// ------------------------------------------------------------------------ // Memory management // // Simply carve off from the front of the PCI mapped window into real memory @@ -937,7 +756,7 @@ ebsa285_i82559_init(struct cyg_netdevtab Mask82559Interrupt(p_i82559); - wait_for_cmd_done(ioaddr + SCBCmd); // make sure no command operating + wait_for_cmd_done(ioaddr); // make sure no command operating i82559_reset(p_i82559); @@ -953,6 +772,7 @@ ebsa285_i82559_init(struct cyg_netdevtab udelay(10); } while ( (p_selftest[1] == -1) && (--count >= 0) ); + Acknowledge82559Interrupt(p_i82559); UnMask82559Interrupt(p_i82559); if (count < 0) { @@ -1044,8 +864,10 @@ static void i82559_start( struct eth_drv struct i82559 *p_i82559; cyg_uint32 ioaddr; #ifdef KEEP_STATISTICS +#ifdef DISPLAY_82559_STATISTICS void *p_statistics; #endif +#endif p_i82559 = (struct i82559 *)sc->driver_private; @@ -1071,27 +893,24 @@ static void i82559_start( struct eth_drv p_i82559->p_statistics = p_statistics = pciwindow_mem_alloc(sizeof(I82559_COUNTERS)); memset(p_statistics, 0xFFFFFFFF, sizeof(I82559_COUNTERS)); - wait_for_cmd_done(ioaddr + SCBCmd); // make sure no command operating + wait_for_cmd_done(ioaddr); // make sure no command operating // set statistics dump address OUTL(VIRT_TO_BUS(p_statistics), ioaddr + SCBPointer); OUTW(SCB_M | CU_STATSADDR, ioaddr + SCBCmd); - wait_for_cmd_done(ioaddr + SCBCmd); // make sure no command operating + wait_for_cmd_done(ioaddr); // make sure no command operating OUTW(SCB_M | CU_DUMPSTATS, ioaddr + SCBCmd); // start register dump #endif #endif - wait_for_cmd_done(ioaddr + SCBCmd); // make sure no command operating - + // Set the base address + wait_for_cmd_done(ioaddr); OUTL(0, ioaddr + SCBPointer); // load ru base address = 0 OUTW(SCB_M | RUC_ADDR_LOAD, ioaddr + SCBCmd); - - wait_for_cmd_done(ioaddr + SCBCmd); // wait for SCB command complete - // load pointer to Rx Ring + udelay( 1000 ); // load pointer to Rx Ring OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), ioaddr + SCBPointer); OUTW(RUC_START, ioaddr + SCBCmd); - p_i82559->out_of_resources = 0; p_i82559->active = 1; if ( 0 @@ -1137,8 +956,8 @@ static void i82559_stop( struct eth_drv_ os_printf("i82559_stop %d flg %x\n", p_i82559->index, *(int *)p_i82559 ); #endif + p_i82559->active = 0; // stop people tormenting it i82559_reset(p_i82559); // that should stop it - p_i82559->active = 0; // and stop people tormenting it ResetRxRing( p_i82559 ); ResetTxRing( p_i82559 ); @@ -1202,22 +1021,26 @@ static void ResetRxRing(struct i82559* p // ------------------------------------------------------------------------ // -// Function : PacketRx +// Function : PacketRxReady (Called from DSR) // // ------------------------------------------------------------------------ static void PacketRxReady(struct i82559* p_i82559) { - struct cyg_netdevtab_entry *ndp; - struct eth_drv_sc *sc; RFD *p_rfd; int next_descriptor; int length; + struct cyg_netdevtab_entry *ndp; + struct eth_drv_sc *sc; + cyg_uint32 ioaddr; + cyg_uint16 status; ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); sc = (struct eth_drv_sc *)(ndp->device_instance); CHECK_NDP_SC_LINK(); + ioaddr = p_i82559->io_address; + next_descriptor = p_i82559->next_rx_descriptor; p_rfd = p_i82559->rx_ring[next_descriptor]; @@ -1253,35 +1076,29 @@ static void PacketRxReady(struct i82559* CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" ); } - if ( p_i82559->out_of_resources ) { // out of Rx resources ? - if ( ! (p_rfd->status & RFD_STATUS_C) ) { // all buffers processed ? - cyg_uint32 ioaddr; - // yes, restart RU -#ifdef KEEP_STATISTICS - statistics[p_i82559->index].rx_restart++; -#endif - next_descriptor = 0; // re-initialize next desc. - p_i82559->out_of_resources = 0; // clear out of resource flag - ioaddr = p_i82559->io_address; // get I/O address + // See if the RU has gone idle (usually because of out of resource + // condition) and restart it if needs be. + Mask82559Interrupt(p_i82559); + status = INW(ioaddr + SCBStatus); + if ( RU_STATUS_READY != (status & RU_STATUS_MASK) ) { + // Acknowledge the RX INT sources + OUTW( SCB_INTACK_RX, ioaddr + SCBStatus); + // (see pages 6-10 & 6-90) - // wait for SCB command complete - wait_for_cmd_done(ioaddr + SCBCmd); - OUTW(RUC_ABORT, ioaddr + SCBCmd); - - // make sure no command operating - wait_for_cmd_done(ioaddr + SCBCmd); +#ifdef KEEP_STATISTICS + statistics[p_i82559->index].rx_restart++; +#endif + next_descriptor = 0; // re-initialize next desc. + // wait for SCB command complete + wait_for_cmd_done(ioaddr); + // load pointer to Rx Ring + OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), + ioaddr + SCBPointer); + OUTW(RUC_START, ioaddr + SCBCmd); + Acknowledge82559Interrupt(p_i82559); + } + UnMask82559Interrupt(p_i82559); - OUTL(0, ioaddr + SCBPointer); // load ru base address = 0 - OUTW(SCB_M | RUC_ADDR_LOAD, ioaddr + SCBCmd); - - // wait for SCB command complete - wait_for_cmd_done(ioaddr + SCBCmd); - // load pointer to Rx Ring - OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), - ioaddr + SCBPointer); - OUTW(RUC_START, ioaddr + SCBCmd); - } - } p_i82559->next_rx_descriptor = next_descriptor; } @@ -1320,7 +1137,7 @@ static void i82559_recv( struct eth_drv_ #ifdef DEBUG_82559 os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n", - p_i82559->index, (int)priv, p_rfd->status, sg_len, total_len); + p_i82559->index, (int)p_i82559, p_rfd->status, sg_len, total_len); #endif // Copy the data to the network stack @@ -1377,7 +1194,6 @@ static void InitTxRing(struct i82559* p_ for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) { p_i82559->tx_ring[i] = (TxCB *)pciwindow_mem_alloc( sizeof(TxCB) + MAX_TX_PACKET_SIZE); - p_i82559->tx_keys[i] = 0; } ResetTxRing(p_i82559); @@ -1398,6 +1214,7 @@ static void ResetTxRing(struct i82559* p #endif ioaddr = p_i82559->io_address; p_i82559->tx_descriptor_add = + p_i82559->tx_descriptor_active = p_i82559->tx_descriptor_remove = 0; p_i82559->tx_in_progress = p_i82559->tx_queue_full = 0; @@ -1418,11 +1235,102 @@ static void ResetTxRing(struct i82559* p p_i82559->tx_keys[i] = 0; } - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); OUTL(0, ioaddr + SCBPointer); - OUTW(CU_CMD_BASE, ioaddr + SCBCmd); + OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd); } +// ------------------------------------------------------------------------ +// +// Function : TxMachine (Called from FG & ISR) +// +// This steps the Tx Machine onto the next record if necessary - allowing +// for missed interrupts, and so on. +// ------------------------------------------------------------------------ + +static void TxMachine(struct i82559* p_i82559) +{ + int tx_descriptor_active; + cyg_uint32 ioaddr; + + tx_descriptor_active = p_i82559->tx_descriptor_active; + ioaddr = p_i82559->io_address; + + // See if the CU is idle when we think it isn't: + // (Recovers from a dropped interrupt) + if ( p_i82559->tx_in_progress ) { + cyg_uint16 status; + status = INW(ioaddr + SCBStatus); + if ( 0 == (status & CU_STATUS_MASK) ) { + // It is idle. So ack the TX interrupts + OUTW( SCB_INTACK_TX, ioaddr + SCBStatus); + // (see pages 6-10 & 6-90) + + // and step on to the next queued tx. + p_i82559->tx_in_progress = 0; + if ( ++tx_descriptor_active >= MAX_TX_DESCRIPTORS ) + tx_descriptor_active = 0; + p_i82559->tx_descriptor_active = tx_descriptor_active; + } + } + + // is the CU idle, and there a next tx to set going? + if ( ( ! p_i82559->tx_in_progress ) + && p_i82559->tx_descriptor_add != tx_descriptor_active ) { + TxCB *p_txcb; + p_txcb = p_i82559->tx_ring[tx_descriptor_active]; + CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" ); + CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" ); +#ifdef DEBUG_82559 + os_printf("Tx %d %x: Starting Engines, KEY %x\n", + p_i82559->index, (int)p_i82559, key ); +#endif + // make sure no command operating + wait_for_cmd_done(ioaddr); + // start Tx operation + OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer); + OUTW(CU_START, ioaddr + SCBCmd); + p_i82559->tx_in_progress = 1; + } +} + +// ------------------------------------------------------------------------ +// +// Function : TxDone (Called from DSR) +// +// This returns Tx's from the Tx Machine to the stack (ie. reports +// completion) - allowing for missed interrupts, and so on. +// ------------------------------------------------------------------------ + +static void TxDone(struct i82559* p_i82559) +{ + struct cyg_netdevtab_entry *ndp; + struct eth_drv_sc *sc; + int tx_descriptor_remove = p_i82559->tx_descriptor_remove; + + ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); + sc = (struct eth_drv_sc *)(ndp->device_instance); + + CHECK_NDP_SC_LINK(); + + // "Done" txen are from here to active, OR + // the remove one if the queue is full AND its status is nonzero: + while ( (tx_descriptor_remove != p_i82559->tx_descriptor_active) || + ( p_i82559->tx_queue_full && + (0 != p_i82559->tx_ring[ tx_descriptor_remove ]->status) ) ) { + unsigned long key = p_i82559->tx_keys[ tx_descriptor_remove ]; +#ifdef DEBUG_82559 + os_printf("TxDone %d %x: KEY %x\n", + p_i82559->index, (int)p_i82559, key ); +#endif + eth_drv_tx_done( sc, key, 1 /* status */ ); + + if ( ++tx_descriptor_remove >= MAX_TX_DESCRIPTORS ) + tx_descriptor_remove = 0; + p_i82559->tx_descriptor_remove = tx_descriptor_remove; + p_i82559->tx_queue_full = 0; + } +} // ------------------------------------------------------------------------ @@ -1444,6 +1352,12 @@ i82559_can_send(struct eth_drv_sc *sc) os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 ); return 0; } + + // Advance TxMachine atomically + Mask82559Interrupt(p_i82559); + TxMachine(p_i82559); + Acknowledge82559Interrupt(p_i82559); + UnMask82559Interrupt(p_i82559); return ! p_i82559->tx_queue_full; } @@ -1473,7 +1387,7 @@ i82559_send(struct eth_drv_sc *sc, #ifdef DEBUG_82559 os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n", - p_i82559->index, (int)priv, sg_len, total_len, key ); + p_i82559->index, (int)p_i82559, sg_len, total_len, key ); #endif if ( ! p_i82559->active ) @@ -1485,7 +1399,7 @@ i82559_send(struct eth_drv_sc *sc, if ( p_i82559->tx_queue_full ) { #ifdef KEEP_STATISTICS - statistics[p_i82559->index].tx_dropped++ + statistics[p_i82559->index].tx_dropped++; #endif os_printf( "i82559_send: Queue full, device %x, key %x\n", p_i82559, key ); @@ -1543,209 +1457,33 @@ i82559_send(struct eth_drv_sc *sc, CYG_ASSERT( &p_txcb->buffer[0] + MAX_TX_PACKET_SIZE >= to_p, "to_p overflow in tx" ); + // Next descriptor if ( ++tx_descriptor_add >= MAX_TX_DESCRIPTORS) tx_descriptor_add = 0; + p_i82559->tx_descriptor_add = tx_descriptor_add; - // no more interrupts until started - Mask82559Interrupt(p_i82559); - - p_i82559->tx_descriptor_add = tx_descriptor_add; - if ( p_i82559->tx_descriptor_remove == tx_descriptor_add ) p_i82559->tx_queue_full = 1; - - if ( ! p_i82559->tx_in_progress ) { // if no Tx operation running -#ifdef DEBUG_82559 - os_printf("Tx %d %x: Starting Engines, KEY %x\n", - p_i82559->index, (int)priv, key ); -#endif - // flag start of Tx operation - p_i82559->tx_in_progress = 1; - // make sure no command operating - wait_for_cmd_done(ioaddr + SCBCmd); - // start Tx operation - OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer); - OUTW(CU_START, ioaddr + SCBCmd); - } - UnMask82559Interrupt(p_i82559); // Allow this device to interrupt } -} - - - -// ------------------------------------------------------------------------ -// -// Function : TxComplete -// -// ------------------------------------------------------------------------ -static unsigned long TxComplete(struct i82559* p_i82559) -{ - int tx_descriptor_remove; - cyg_uint32 ioaddr; - TxCB *p_txcb; - unsigned long key; - - tx_descriptor_remove = p_i82559->tx_descriptor_remove; - - CYG_ASSERT( p_i82559->tx_in_progress, "Tx not in progress but Tx intr" ); - - key = p_i82559->tx_keys[tx_descriptor_remove]; - if ( ++tx_descriptor_remove >= MAX_TX_DESCRIPTORS ) - tx_descriptor_remove = 0; - p_i82559->tx_descriptor_remove = tx_descriptor_remove; - p_i82559->tx_queue_full = 0; - if ( p_i82559->tx_descriptor_add != tx_descriptor_remove ) { - // get device I/O address - ioaddr = p_i82559->io_address; - p_txcb = p_i82559->tx_ring[tx_descriptor_remove]; - CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" ); - CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" ); - // make sure no command operating - wait_for_cmd_done(ioaddr + SCBCmd); - // start Tx operation - OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer); - OUTW(CU_START, ioaddr + SCBCmd); - } - else - p_i82559->tx_in_progress = 0; + // Try advancing the Tx Machine regardless - return key; -} - -// ------------------------------------------------------------------------ - -static void -PacketTxDone(struct i82559* p_i82559, unsigned long key) -{ - struct cyg_netdevtab_entry *ndp; - struct eth_drv_sc *sc; - - // Just tell the stack that this device has done a Tx. - ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); - sc = (struct eth_drv_sc *)(ndp->device_instance); - - CHECK_NDP_SC_LINK(); - -#ifdef DEBUG_82559 - os_printf("TxDone %d %x: KEY %x\n", - p_i82559->index, (int)p_i82559, key ); -#endif - - eth_drv_tx_done( sc, key, 1 /* status */ ); -} - - -// ------------------------------------------------------------------------ -// -// Function : QueueThreadRequest -// -// ------------------------------------------------------------------------ -static void QueueThreadRequest(int type, - struct i82559* p_i82559, - unsigned long key) -{ - if ( ! i82559_q_full ) { - - i82559_queue[i82559_q_in].request = type; - i82559_queue[i82559_q_in].p = p_i82559; - i82559_queue[i82559_q_in].key = key; - - if ( ++i82559_q_in >= I82559_QUEUE_SIZE ) - i82559_q_in = 0; + // no more interrupts until started + Mask82559Interrupt(p_i82559); - if ( i82559_q_in == i82559_q_out ) - i82559_q_full = 1; - } -} - - - -// ------------------------------------------------------------------------ -// -// Function : i82559_isr -// -// ------------------------------------------------------------------------ -int last_status[16] = { 0 }; -int last_index = 0; - -static int i82559_isr(struct i82559* p_i82559) -{ - cyg_uint16 status; - cyg_uint32 io_address; - int return_value; - - IF_BAD_82559( p_i82559 ) { - os_printf( "i82559_isr: Bad device pointer %x\n", p_i82559 ); - return 0; - } - - io_address = p_i82559->io_address; - status = INW(io_address + SCBStatus); - OUTW(status & 0xFC00, io_address + SCBStatus); - - return_value = 0; - - last_status[last_index++] = status; - last_status[last_index &= 15] = -1; - - // receiver left ready state ? - if ( status & SCB_STATUS_RNR ) { -#ifdef KEEP_STATISTICS - statistics[p_i82559->index].rx_resource++; -#endif - // flag out of resources - p_i82559->out_of_resources = 1; - } + // Check that either: + // tx is already active, there is other stuff queued, + // OR this tx just added is the current active one. + CYG_ASSERT( (p_i82559->tx_in_progress == 1) || + ((p_i82559->tx_descriptor_add-1) == p_i82559->tx_descriptor_active) + || ((0 == p_i82559->tx_descriptor_add) && + ((MAX_TX_DESCRIPTORS-1) == p_i82559->tx_descriptor_active)), + "Active/add mismatch" ); - // frame receive interrupt ? - if ( status & SCB_STATUS_FR ) { -#ifdef KEEP_STATISTICS - statistics[p_i82559->index].rx_count++; -#endif - QueueThreadRequest(PACKET_RX, p_i82559, 0); - return_value = 1; - } - - // transmit interrupt ? - if ( status & SCB_STATUS_CX ) { - unsigned long key; -#ifdef KEEP_STATISTICS - statistics[p_i82559->index].tx_complete++; -#endif - key = TxComplete(p_i82559); - QueueThreadRequest(PACKET_TX, p_i82559, key); - return_value = 1; - } - - return return_value; -} - -// ------------------------------------------------------------------------ -// -// Function : i82559_mux_isr -// -// ------------------------------------------------------------------------ -static int i82559_mux_isr(void) -{ - int return_value = 0; - - static int mux_device_index = 0; - - int device_index = mux_device_index; - - return_value = i82559_isr( &i82559[device_index] ); - - mux_device_index ^= 1; // look at the other one first next time. - - if ( return_value ) - return return_value; - - device_index = mux_device_index; - - return_value = i82559_isr( &i82559[device_index] ); - - return return_value; + // Advance TxMachine atomically + TxMachine(p_i82559); + Acknowledge82559Interrupt(p_i82559); + UnMask82559Interrupt(p_i82559); } // ------------------------------------------------------------------------ @@ -1760,7 +1498,7 @@ static void i82559_reset(struct i82559* ioaddr = p_i82559->io_address; // make sure no command operating - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); OUTL(I82559_SELECTIVE_RESET, ioaddr + SCBPort); @@ -1778,6 +1516,313 @@ static void i82559_reset(struct i82559* // ------------------------------------------------------------------------ // +// INTERRUPT HANDLERS +// +// ------------------------------------------------------------------------ + +static cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data) +{ + struct i82559* p_i82559 = (struct i82559 *)data; + cyg_uint16 status; + cyg_uint32 ioaddr; + + IF_BAD_82559( p_i82559 ) { + os_printf( "i82559_isr: Bad device pointer %x\n", p_i82559 ); + return 0; + } + + ioaddr = p_i82559->io_address; + status = INW(ioaddr + SCBStatus); + // Acknowledge all INT sources that were active + OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus); + // (see pages 6-10 & 6-90) + +#ifdef KEEP_STATISTICS + statistics[p_i82559->index].interrupts++; + + // receiver left ready state ? + if ( status & SCB_STATUS_RNR ) + statistics[p_i82559->index].rx_resource++; + + // frame receive interrupt ? + if ( status & SCB_STATUS_FR ) + statistics[p_i82559->index].rx_count++; + + // transmit interrupt ? + if ( status & SCB_STATUS_CX ) + statistics[p_i82559->index].tx_complete++; +#endif + + // Advance the Tx Machine regardless + TxMachine(p_i82559); + + // it should have settled down now... + Acknowledge82559Interrupt(p_i82559); + + return CYG_ISR_CALL_DSR; // schedule DSR +} + + +// ------------------------------------------------------------------------ +static int mux_device_index = 0; + +static cyg_uint32 eth_mux_isr(cyg_vector_t vector, cyg_addrword_t data) +{ + int device_index = mux_device_index; + struct i82559* p_i82559; + + mux_device_index ^= 1; // look at the other one first next time. + + do { + p_i82559 = &i82559[device_index]; + if ( p_i82559->active ) + (void)eth_isr( vector, (cyg_addrword_t)p_i82559 ); + device_index ^= 1; + } while ( device_index == mux_device_index ); + + return CYG_ISR_CALL_DSR; +} + +// ------------------------------------------------------------------------ + +void eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + struct i82559* p_i82559 = (struct i82559 *)data; + + // First pass any rx data up the stack + PacketRxReady(p_i82559); + + // Then scan for completed Txen and inform the stack + TxDone(p_i82559); +} + + +// ------------------------------------------------------------------------ +void eth_mux_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + int device_index = mux_device_index; + struct i82559* p_i82559; + + mux_device_index ^= 1; // look at the other one first next time. + // (non-atomicity wrt IRQ does not matter) + do { + p_i82559 = &i82559[device_index]; + if ( p_i82559->active ) + eth_dsr( vector, count, (cyg_addrword_t)p_i82559 ); + device_index ^= 1; + } while ( device_index == mux_device_index ); +} + +// ------------------------------------------------------------------------ +// +// Function : pci_init_find_82559s +// +// This is called exactly once at the start of time to: +// o scan the PCI bus for objects +// o record them in the device table +// o acquire all the info needed for the driver to access them +// o instantiate interrupts for them +// o attach those interrupts appropriately +// ------------------------------------------------------------------------ +static int +pci_init_find_82559s( void ) +{ + cyg_pci_device_id devid; + cyg_pci_device dev_info; + cyg_uint16 cmd; + int device_index; + + // MUX interrupt - special case when 2 cards share one intr. + static cyg_handle_t mux_interrupt_handle = 0; + static cyg_interrupt mux_interrupt_object; + +#ifdef DEBUG + db_printf("pci_init_find_82559s()\n"); +#endif + + // allocate memory to be used in ioctls later + if (mem_reserved_ioctl != (void*)0) { + db_printf("pci_init_find_82559s() called > once\n"); + return 0; + } + + // First initialize the heap in PCI window'd memory + i82559_heap_size = CYGHWR_HAL_ARM_EBSA285_PCI_MEM_MAP_SIZE; + i82559_heap_base = (cyg_uint8 *)CYGHWR_HAL_ARM_EBSA285_PCI_MEM_MAP_BASE; + i82559_heap_free = i82559_heap_base; + + mem_reserved_ioctl = pciwindow_mem_alloc(MAX_MEM_RESERVED_IOCTL); + + cyg_pci_init(); +#ifdef DEBUG + db_printf("Finished cyg_pci_init();\n"); +#endif + devid = CYG_PCI_NULL_DEVID; + + for (device_index = 0; device_index < MAX_82559; device_index++) { + struct i82559 *p_i82559 = &i82559[device_index]; + p_i82559->index = device_index; + + if (cyg_pci_find_device(0x8086, 0x1229, &devid) ) { +#ifdef DEBUG + db_printf("eth%d = 82559\n", device_index); +#endif + cyg_pci_get_device_info(devid, &dev_info); + + if (cyg_pci_translate_interrupt(&dev_info, &p_i82559->vector)) { +#ifdef DEBUG + db_printf(" Wired to HAL vector %d\n", p_i82559->vector); +#endif + cyg_drv_interrupt_create( + p_i82559->vector, + 0, // Priority - unused + (CYG_ADDRWORD)p_i82559, // Data item passed to ISR & DSR + eth_isr, // ISR + eth_dsr, // DSR + &p_i82559->interrupt_handle, // handle to intr obj + &p_i82559->interrupt_object ); // space for int obj + + cyg_drv_interrupt_attach(p_i82559->interrupt_handle); + + // Don't unmask the interrupt yet, that could get us into a + // race. + + // ALSO attach it to interrupt #18 for multiplexed + // interrupts. This is for certain boards where the + // PCI backplane is wired "straight through" instead of + // with a rotation of interrupt lines in the different + // slots. + if ( ! mux_interrupt_handle ) { +#ifdef DEBUG + db_printf(" Also attaching to HAL vector %d\n", + CYGNUM_HAL_INTERRUPT_PCI_IRQ); +#endif + cyg_drv_interrupt_create( + CYGNUM_HAL_INTERRUPT_PCI_IRQ, + 0, // Priority - unused + 0, // Data item passed to ISR (not used) + eth_mux_isr, // ISR + eth_mux_dsr, // DSR + &mux_interrupt_handle, + &mux_interrupt_object ); + + cyg_drv_interrupt_attach(mux_interrupt_handle); + } + } + else { + p_i82559->vector=0; +#ifdef DEBUG + db_printf(" Does not generate interrupts.\n"); +#endif + } + + if (cyg_pci_configure_device(&dev_info)) { +#ifdef DEBUG + int i; + db_printf("Found device on bus %d, devfn 0x%02x:\n", + CYG_PCI_DEV_GET_BUS(devid), + CYG_PCI_DEV_GET_DEVFN(devid)); + + if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) { + db_printf(" Note that board is active. Probed" + " sizes and CPU addresses invalid!\n"); + } + db_printf(" Vendor 0x%04x", dev_info.vendor); + db_printf("\n Device 0x%04x", dev_info.device); + db_printf("\n Command 0x%04x, Status 0x%04x\n", + dev_info.command, dev_info.status); + + db_printf(" Class/Rev 0x%08x", dev_info.class_rev); + db_printf("\n Header 0x%02x\n", dev_info.header_type); + + db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n", + dev_info.header.normal.sub_vendor, + dev_info.header.normal.sub_id); + + for(i = 0; i < CYG_PCI_MAX_BAR; i++) { + db_printf(" BAR[%d] 0x%08x /", i, dev_info.base_address[i]); + db_printf(" probed size 0x%08x / CPU addr 0x%08x\n", + dev_info.base_size[i], dev_info.base_map[i]); + } + db_printf(" eth%d configured\n", device_index); +#endif + p_i82559->found = 1; + p_i82559->active = 0; + p_i82559->devid = devid; + p_i82559->memory_address = dev_info.base_map[0]; + p_i82559->io_address = dev_info.base_map[1]; +#ifdef DEBUG + db_printf(" memory address = 0x%08x\n", dev_info.base_map[0]); + db_printf(" I/O address = 0x%08x\n", dev_info.base_map[1]); +#endif + + // Don't use cyg_pci_set_device_info since it clears + // some of the fields we want to print out below. + cyg_pci_read_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, &cmd); + cmd |= CYG_PCI_CFG_COMMAND_IO // enable I/O space + | CYG_PCI_CFG_COMMAND_MEMORY // enable memory space + | CYG_PCI_CFG_COMMAND_MASTER; // enable bus master + cyg_pci_write_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, cmd); + + // Now the PCI part of the device is configured, reset it. This + // should make it safe to enable the interrupt + i82559_reset(p_i82559); + + if (p_i82559->vector != 0) { + cyg_interrupt_acknowledge(p_i82559->vector); + cyg_drv_interrupt_unmask(p_i82559->vector); + } +#ifdef DEBUG + db_printf(" **** Device enabled for I/O and Memory and Bus Master\n"); +#endif + } + else { + p_i82559->found = 0; + p_i82559->active = 0; + db_printf("Failed to configure device %d\n",device_index); + } + } + else { + p_i82559->found = 0; + p_i82559->active = 0; + db_printf("eth%d not found\n", device_index); + } + } + + // Now enable the mux shared interrupt if it is in use + if (mux_interrupt_handle) { + cyg_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_PCI_IRQ); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_PCI_IRQ); + } + + return 1; +} + + +// ------------------------------------------------------------------------ +// We use this as a templete when writing a new MAC address into the +// eeproms. The MAC address in the first few bytes is over written +// with the correct MAC address and then the whole lot is programmed +// into the serial EEPROM. The checksum is calculated on the fly and +// sent instead of the last two bytes. + +static char eeprom_burn[126] = { + 0x00, 0x90, 0x27, 0x8c, 0x57, 0x82, 0x03, 0x02, 0x00, 0x00, 0x01, + 0x02, 0x01, 0x47, 0x00, 0x00, 0x13, 0x72, 0x06, 0x83, 0xa2, 0x40, + 0x0c, 0x00, 0x86, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// ------------------------------------------------------------------------ +// // Function : eth_set_promiscuous_mode // // Return : 0 = It worked. @@ -1796,14 +1841,14 @@ static int eth_set_promiscuous_mode(stru } ioaddr = p_i82559->io_address; - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); // load cu base address = 0 */ OUTL(0, ioaddr + SCBPointer); // 32 bit linear addressing used - OUTW(SCB_M | CUC_ADDR_LOAD, ioaddr + SCBCmd); + OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd); // wait for SCB command complete - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); ccs = (CONFIG_CMD_STRUCT *)mem_reserved_ioctl; @@ -1844,13 +1889,13 @@ static int eth_set_promiscuous_mode(stru ccs->config_bytes[18]=0x70; // wait for SCB command complete - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); OUTL(VIRT_TO_BUS(ccs), ioaddr + SCBPointer); - OUTW(SCB_M | CUC_START, ioaddr + SCBCmd); + OUTW(SCB_M | CU_START, ioaddr + SCBCmd); // now check for result ... - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); if ( (!ccs->cb_entry.cb_ok) || (!ccs->cb_entry.cb_complete) ) return 1; // Failed @@ -1879,14 +1924,14 @@ static int eth_set_mac_address(struct i8 ioaddr = p_i82559->io_address; - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); // load cu base address = 0 */ OUTL(0, ioaddr + SCBPointer); // 32 bit linear addressing used - OUTW(SCB_M | CUC_ADDR_LOAD, ioaddr + SCBCmd); + OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd); // wait for SCB command complete - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); ccs = (CONFIG_CMD_STRUCT *)mem_reserved_ioctl; if (ccs == (void*)0) @@ -1907,12 +1952,12 @@ static int eth_set_mac_address(struct i8 ioaddr = p_i82559->io_address; OUTL(VIRT_TO_BUS(ccs), ioaddr + SCBPointer); - OUTW(SCB_M | CUC_START, ioaddr + SCBCmd); + OUTW(SCB_M | CU_START, ioaddr + SCBCmd); // Next delay seems to be required, otherwise, // cb_ok/cb_complete won't be set later. udelay(100); - wait_for_cmd_done(ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr); // now check for result ... if ( (!ccs->cb_entry.cb_ok) || (!ccs->cb_entry.cb_complete) ) @@ -2105,266 +2150,200 @@ static int i82559_ioctl(struct eth_drv_s // ------------------------------------------------------------------------ // -// INTERRUPT HANDLERS +// +// CODE FOR DEBUGGING PURPOSES ONLY +// // // ------------------------------------------------------------------------ - -static cyg_uint32 eth_isr(cyg_vector_t vector, cyg_addrword_t data) +void dump_txcb(TxCB *p_txcb) { - int schedule_dsr; - - cyg_drv_interrupt_mask(vector); // mask this interrupt - - schedule_dsr = i82559_isr( (struct i82559 *)data ); // process interrupt - - cyg_drv_interrupt_acknowledge(vector); // acknowledge interrupt - - // schedule further processing ? - if ( schedule_dsr ) - return CYG_ISR_CALL_DSR; // yes, schedule DSR - - // else... - cyg_drv_interrupt_unmask(vector); // allow more of these interrupts - return CYG_ISR_HANDLED; + os_printf("TxCB @ %x\n", (int)p_txcb); + os_printf("status = %04X ", p_txcb->status); + os_printf("command = %04X ", p_txcb->command); + os_printf("link = %08X ", p_txcb->link); + os_printf("tbd = %08X ", p_txcb->tbd_address); + os_printf("count = %d ", p_txcb->count); + os_printf("eof = %x ", p_txcb->eof); + os_printf("threshold = %d ", p_txcb->tx_threshold); + os_printf("tbd number = %d\n", p_txcb->tbd_number); } - -static cyg_uint32 eth_mux_isr(cyg_vector_t vector, cyg_addrword_t data) +// This is intended to be the body of a THREAD that prints stuff every 10 +// seconds or so: +#ifdef KEEP_STATISTICS +#ifdef DISPLAY_STATISTICS +void DisplayStatistics(void) { - int schedule_dsr; - - cyg_drv_interrupt_mask( vector ); // mask this interrupt - - schedule_dsr = i82559_mux_isr(); // process interrupt + int i; + I82559_COUNTERS *p_statistics; + cyg_uint32 *p_counter; + cyg_uint32 *p_register; + int reg_count; + int status; + + while ( 1 ) { +#ifdef DISPLAY_82559_STATISTICS + for ( i = 0; i < 2; i ++ ) { + p_statistics = (I82559_COUNTERS *)i82559[i].p_statistics; + if ( (p_statistics->done & 0xFFFF) == 0xA007 ) { + p_counter = (cyg_uint32 *)&i82559_counters[i]; + p_register = (cyg_uint32 *)&p_statistics->tx_good; + for ( reg_count = 20; reg_count != 0; reg_count--) { + *p_counter += *p_register; + p_counter++; + p_register++; + } + p_statistics->done = 0; + // make sure no command operating + wait_for_cmd_done(i82559[i].io_address); + // start register dump + OUTW(CU_DUMPSTATS, i82559[i].io_address + SCBCmd); + } + } +#endif + os_printf("\nRx\nPackets = %d %d\n", + statistics[0].rx_count, statistics[1].rx_count); + os_printf("Deliver %d %d\n", + statistics[0].rx_deliver, statistics[1].rx_deliver); + os_printf("Resource %d %d\n", + statistics[0].rx_resource, statistics[1].rx_resource); + os_printf("Restart %d %d\n", + statistics[0].rx_restart, statistics[1].rx_restart); - cyg_drv_interrupt_acknowledge( vector ); // ack interrupt +#ifdef DISPLAY_82559_STATISTICS + os_printf("Count %d %d\n", + i82559_counters[0].rx_good, i82559_counters[1].rx_good); + os_printf("CRC %d %d\n", + i82559_counters[0].rx_crc_errors, i82559_counters[1].rx_crc_errors); + os_printf("Align %d %d\n", + i82559_counters[0].rx_align_errors, i82559_counters[1].rx_align_errors); + os_printf("Resource %d %d\n", + i82559_counters[0].rx_resource_errors, i82559_counters[1].rx_resource_errors); + os_printf("Overrun %d %d\n", + i82559_counters[0].rx_overrun_errors, i82559_counters[1].rx_overrun_errors); + os_printf("Collision %d %d\n", + i82559_counters[0].rx_collisions, i82559_counters[1].rx_collisions); + os_printf("Short %d %d\n", + i82559_counters[0].rx_short_frames, i82559_counters[1].rx_short_frames); +#endif + os_printf("\nTx\nPackets = %d %d\n", + statistics[0].tx_count, statistics[1].tx_count); + os_printf("Complete %d %d\n", + statistics[0].tx_complete, statistics[1].tx_complete); + os_printf("Dropped %d %d\n", + statistics[0].tx_dropped, statistics[1].tx_dropped); + os_printf("Count %d %d\n", + i82559_counters[0].tx_good, i82559_counters[1].tx_good); +#ifdef DISPLAY_82559_STATISTICS + os_printf("Collision %d %d\n", + i82559_counters[0].tx_max_collisions,i82559_counters[1].tx_max_collisions); + os_printf("Late Col. %d %d\n", + i82559_counters[0].tx_late_collisions,i82559_counters[1].tx_late_collisions); + os_printf("Underrun %d %d\n", + i82559_counters[0].tx_underrun,i82559_counters[1].tx_underrun); + os_printf("Carrier %d %d\n", + i82559_counters[0].tx_carrier_loss,i82559_counters[1].tx_carrier_loss); + os_printf("Deferred %d %d\n", + i82559_counters[0].tx_deferred, i82559_counters[1].tx_deferred); + os_printf("1 Col %d %d\n", + i82559_counters[0].tx_single_collisions, i82559_counters[0].tx_single_collisions); + os_printf("Mult. Col %d %d\n", + i82559_counters[0].tx_mult_collisions, i82559_counters[0].tx_mult_collisions); + os_printf("Total Col %d %d\n", + i82559_counters[0].tx_total_collisions, i82559_counters[0].tx_total_collisions); +#endif + status = INB(i82559[0].io_address + SCBGenStatus); + os_printf("Interface 0 Link = %s, %s Mbps, %s Duplex\n", + status & GEN_STATUS_LINK ? "Up" : "Down", + status & GEN_STATUS_100MBPS ? "100" : "10", + status & GEN_STATUS_FDX ? "Full" : "Half"); + + status = INB(i82559[1].io_address + SCBGenStatus); + os_printf("Interface 1 Link = %s, %s Mbps, %s Duplex\n", + status & GEN_STATUS_LINK ? "Up" : "Down", + status & GEN_STATUS_100MBPS ? "100" : "10", + status & GEN_STATUS_FDX ? "Full" : "Half"); + + cyg_thread_delay(1000); + } +} +#endif // DISPLAY_STATISTICS +#endif // KEEP_STATISTICS - // schedule further processing ? - if ( schedule_dsr ) - return CYG_ISR_CALL_DSR; // yes, schedule DSR - - // else... - cyg_drv_interrupt_unmask( vector ); // allow more of these interrupts - return CYG_ISR_HANDLED; +void dump_rfd(RFD *p_rfd, int anyway ) +{ + if ( (0 != p_rfd->status) || anyway ) { + os_printf("RFD @ %x = ", (int)p_rfd); + os_printf("status = %x ", p_rfd->status); + os_printf("link = %x ", p_rfd->link); +// os_printf("rdb_address = %x ", p_rfd->rdb_address); + os_printf("count = %x ", p_rfd->count); + os_printf("f = %x ", p_rfd->f); + os_printf("eof = %x ", p_rfd->eof); + os_printf("size = %x\n", p_rfd->size); + os_printf("[%04x %04x %04x] ", + *((cyg_uint16 *)(&(p_rfd->buffer[0]))), + *((cyg_uint16 *)(&(p_rfd->buffer[2]))), + *((cyg_uint16 *)(&(p_rfd->buffer[4]))) ); + os_printf("[%04x %04x %04x] %04x : ", + *((cyg_uint16 *)(&(p_rfd->buffer[6]))), + *((cyg_uint16 *)(&(p_rfd->buffer[8]))), + *((cyg_uint16 *)(&(p_rfd->buffer[10]))), + *((cyg_uint16 *)(&(p_rfd->buffer[12]))) ); + os_printf("(%04x %04x %04x %04x) ", + *((cyg_uint16 *)(&(p_rfd->buffer[14]))), + *((cyg_uint16 *)(&(p_rfd->buffer[16]))), + *((cyg_uint16 *)(&(p_rfd->buffer[18]))), + *((cyg_uint16 *)(&(p_rfd->buffer[20]))) ); + os_printf("[%04x %04x %04x] ", + *((cyg_uint16 *)(&(p_rfd->buffer[22]))), + *((cyg_uint16 *)(&(p_rfd->buffer[24]))), + *((cyg_uint16 *)(&(p_rfd->buffer[26]))) ); + os_printf("%d.%d.%d.%d ", + *((cyg_uint8 *)(&(p_rfd->buffer[28]))), + *((cyg_uint8 *)(&(p_rfd->buffer[29]))), + *((cyg_uint8 *)(&(p_rfd->buffer[30]))), + *((cyg_uint8 *)(&(p_rfd->buffer[31]))) ); + os_printf("[%04x %04x %04x] ", + *((cyg_uint16 *)(&(p_rfd->buffer[32]))), + *((cyg_uint16 *)(&(p_rfd->buffer[34]))), + *((cyg_uint16 *)(&(p_rfd->buffer[36]))) ); + os_printf("%d.%d.%d.%d ...\n", + *((cyg_uint8 *)(&(p_rfd->buffer[38]))), + *((cyg_uint8 *)(&(p_rfd->buffer[39]))), + *((cyg_uint8 *)(&(p_rfd->buffer[40]))), + *((cyg_uint8 *)(&(p_rfd->buffer[41]))) ); + } +} + +void dump_all_rfds( int intf ) +{ + struct i82559* p_i82559 = &i82559[intf]; + int i, j; + j = p_i82559->next_rx_descriptor; + os_printf("rx descriptors for interface %d (eth%d):\n", intf, intf ); + for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) + dump_rfd( p_i82559->rx_ring[i], (i > (j-3) && (i <= j)) ); + os_printf("next rx descriptor = %x\n\n", j); +} + + +void dump_packet(cyg_uint8 *p_buffer, int length) +{ + int count; + + count = 0; + while ( length > 0 ) { + if ( count == 0 ) + os_printf("\n"); + count = (count + 1) & 0x0F; + os_printf("%02X ", *p_buffer++); + length--; + } + os_printf("\n"); } // ------------------------------------------------------------------------ -void eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) -{ - while ( (i82559_q_out != i82559_q_in) || (i82559_q_full) ) { - switch ( i82559_queue[i82559_q_out].request ) { - case PACKET_RX: - PacketRxReady(i82559_queue[i82559_q_out].p); - break; - - case PACKET_TX: - PacketTxDone(i82559_queue[i82559_q_out].p, - i82559_queue[i82559_q_out].key); - break; - } - i82559_q_full = 0; - if ( ++i82559_q_out == I82559_QUEUE_SIZE ) - i82559_q_out = 0; - } - // allow interrupts to continue from whichever source - // (if multiple device actions were dispatched in this DSR call, - // another call will occur almost immediately) - cyg_drv_interrupt_unmask(vector); -} - -// ------------------------------------------------------------------------ -// -// Function : pci_init_find_82559s -// -// This is called exactly once at the start of time to: -// o scan the PCI bus for objects -// o record them in the device table -// o acquire all the info needed for the driver to access them -// o instantiate interrupts for them -// o attach those interrupts appropriately -// ------------------------------------------------------------------------ -static int -pci_init_find_82559s( void ) -{ - cyg_pci_device_id devid; - cyg_pci_device dev_info; - cyg_uint16 cmd; - int device_index; - - // MUX interrupt - special case when 2 cards share one intr. - static cyg_handle_t mux_interrupt_handle = 0; - static cyg_interrupt mux_interrupt_object; - -#ifdef DEBUG - db_printf("pci_init_find_82559s()\n"); -#endif - - // allocate memory to be used in ioctls later - if (mem_reserved_ioctl != (void*)0) { - db_printf("pci_init_find_82559s() called > once\n"); - return 0; - } - - // First initialize the heap in PCI window'd memory - i82559_heap_size = CYGHWR_HAL_ARM_EBSA285_PCI_MEM_MAP_SIZE; - i82559_heap_base = (cyg_uint8 *)CYGHWR_HAL_ARM_EBSA285_PCI_MEM_MAP_BASE; - i82559_heap_free = i82559_heap_base; - - mem_reserved_ioctl = pciwindow_mem_alloc(MAX_MEM_RESERVED_IOCTL); - - // initialize the event queue for DSR actions - i82559_q_out = i82559_q_in = 0; - i82559_q_full = 0; - - cyg_pci_init(); -#ifdef DEBUG - db_printf("Finished cyg_pci_init();\n"); -#endif - devid = CYG_PCI_NULL_DEVID; - - for (device_index = 0; device_index < MAX_82559; device_index++) { - struct i82559 *p_i82559 = &i82559[device_index]; - p_i82559->index = device_index; - - if (cyg_pci_find_device(0x8086, 0x1229, &devid) ) { -#ifdef DEBUG - db_printf("eth%d = 82559\n", device_index); -#endif - cyg_pci_get_device_info(devid, &dev_info); - - if (cyg_pci_translate_interrupt(&dev_info, &p_i82559->vector)) { -#ifdef DEBUG - db_printf(" Wired to HAL vector %d\n", p_i82559->vector); -#endif - cyg_drv_interrupt_create( - p_i82559->vector, - 0, // Priority - unused - (CYG_ADDRWORD)p_i82559, // Data item passed to ISR - eth_isr, // ISR - eth_dsr, // DSR - &p_i82559->interrupt_handle, // handle to intr obj - &p_i82559->interrupt_object ); // space for int obj - - cyg_drv_interrupt_attach(p_i82559->interrupt_handle); - - // Don't unmask the interrupt yet, that could get us into a - // race. - - // ALSO attach it to interrupt #18 for multiplexed - // interrupts. This is for certain boards where the - // PCI backplane is wired "straight through" instead of - // with a rotation of interrupt lines in the different - // slots. - if ( ! mux_interrupt_handle ) { -#ifdef DEBUG - db_printf(" Also attaching to HAL vector %d\n", - CYGNUM_HAL_INTERRUPT_PCI_IRQ); -#endif - cyg_drv_interrupt_create( - CYGNUM_HAL_INTERRUPT_PCI_IRQ, - 0, // Priority - unused - 0, // Data item passed to ISR (not used) - eth_mux_isr, // ISR - eth_dsr, // DSR - &mux_interrupt_handle, - &mux_interrupt_object ); - - cyg_drv_interrupt_attach(mux_interrupt_handle); - } - } - else { - p_i82559->vector=0; -#ifdef DEBUG - db_printf(" Does not generate interrupts.\n"); -#endif - } - - if (cyg_pci_configure_device(&dev_info)) { -#ifdef DEBUG - int i; - db_printf("Found device on bus %d, devfn 0x%02x:\n", - CYG_PCI_DEV_GET_BUS(devid), - CYG_PCI_DEV_GET_DEVFN(devid)); - - if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) { - db_printf(" Note that board is active. Probed" - " sizes and CPU addresses invalid!\n"); - } - db_printf(" Vendor 0x%04x", dev_info.vendor); - db_printf("\n Device 0x%04x", dev_info.device); - db_printf("\n Command 0x%04x, Status 0x%04x\n", - dev_info.command, dev_info.status); - - db_printf(" Class/Rev 0x%08x", dev_info.class_rev); - db_printf("\n Header 0x%02x\n", dev_info.header_type); - - db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n", - dev_info.header.normal.sub_vendor, - dev_info.header.normal.sub_id); - - for(i = 0; i < CYG_PCI_MAX_BAR; i++) { - db_printf(" BAR[%d] 0x%08x /", i, dev_info.base_address[i]); - db_printf(" probed size 0x%08x / CPU addr 0x%08x\n", - dev_info.base_size[i], dev_info.base_map[i]); - } - db_printf(" eth%d configured\n", device_index); -#endif - p_i82559->found = 1; - p_i82559->active = 0; - p_i82559->devid = devid; - p_i82559->memory_address = dev_info.base_map[0]; - p_i82559->io_address = dev_info.base_map[1]; -#ifdef DEBUG - db_printf(" memory address = 0x%08x\n", dev_info.base_map[0]); - db_printf(" I/O address = 0x%08x\n", dev_info.base_map[1]); -#endif - - // Don't use cyg_pci_set_device_info since it clears - // some of the fields we want to print out below. - cyg_pci_read_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, &cmd); - cmd |= CYG_PCI_CFG_COMMAND_IO // enable I/O space - | CYG_PCI_CFG_COMMAND_MEMORY // enable memory space - | CYG_PCI_CFG_COMMAND_MASTER; // enable bus master - cyg_pci_write_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, cmd); - - // Now the PCI part of the device is configured, reset it. This - // should make it safe to enable the interrupt - i82559_reset(p_i82559); - - if (p_i82559->vector != 0) { - cyg_interrupt_acknowledge(p_i82559->vector); - cyg_drv_interrupt_unmask(p_i82559->vector); - } -#ifdef DEBUG - db_printf(" **** Device enabled for I/O and Memory and Bus Master\n"); -#endif - } - else { - p_i82559->found = 0; - p_i82559->active = 0; - db_printf("Failed to configure device %d\n",device_index); - } - } - else { - p_i82559->found = 0; - p_i82559->active = 0; - db_printf("eth%d not found\n", device_index); - } - } - - // Now enable the mux shared interrupt if it is in use - if (mux_interrupt_handle) { - cyg_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_PCI_IRQ); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_PCI_IRQ); - } - - return 1; -} - - - -// ------------------------------------------------------------------------ - // EOF if_ebsa285.c
--- a/packages/ecos.db +++ b/packages/ecos.db @@ -210,6 +210,31 @@ package CYGPKG_IO_SERIAL_SH_EDK7708 { } +package CYGPKG_DEVS_ETH_ARM_EDB7XXX { + alias { "Cirrus Logic ethernet driver" edb7xxx_eth_driver } + hardware + directory devs/eth/arm/edb7xxx + script edb7xxx_eth_drivers.cdl + description "Ethernet driver for Cirrus Logic EDB7xxx development boards." +} + +package CYGPKG_DEVS_ETH_ARM_EBSA285 { + alias { "Intel EBSA285 with PRO/100+ ethernet driver" + devs_eth_arm_ebsa285 ebsa285_eth_driver } + hardware + directory devs/eth/arm/ebsa285 + script ebsa285_eth_drivers.cdl + description "Ethernet driver for Intel EBSA285 with PRO/100+ boards." +} + +package CYGPKG_DEVS_ETH_POWERPC_QUICC { + alias { "QUICC ethernet driver" quicc_eth_driver } + hardware + directory devs/eth/powerpc/quicc + script quicc_eth_drivers.cdl + description "Ethernet driver for PowerPC QUICC (MPC8xx) based boards." +} + package CYGPKG_IO_PCI { alias { "PCI configuration library" io_pci } directory io/pci
--- a/packages/hal/sh/arch/current/ChangeLog +++ b/packages/hal/sh/arch/current/ChangeLog @@ -1,3 +1,17 @@ +2000-04-26 Jesper Skov <jskov@redhat.com> + + * src/hal_mk_defs.c: Added some caching data. + + * src/vectors.S: + * include/hal_cache.h: + Rewrote caching functions in assembly with appropriate magic to + have the code execute out of a non-cachable memory shadow. + +2000-04-25 Jesper Skov <jskov@redhat.com> + + * include/hal_cache.h (HAL_UCACHE_WRITE_MODE): Also wiggle the WT + bit. It has opposite polarity of the CB bit. + 2000-04-12 Jesper Skov <jskov@redhat.com> * src/vectors.S: Entry code rewritten to allow ROMRAM startups.
--- a/packages/hal/sh/arch/current/include/hal_cache.h +++ b/packages/hal/sh/arch/current/include/hal_cache.h @@ -61,6 +61,8 @@ //----------------------------------------------------------------------------- // Cache dimensions - one unified cache +#define HAL_CACHE_UNIFIED + #define HAL_UCACHE_SIZE CYGARC_SH_MOD_CAC_SIZE #define HAL_UCACHE_LINE_SIZE CYGARC_SH_MOD_CAC_LINE_SIZE #define HAL_UCACHE_WAYS CYGARC_SH_MOD_CAC_WAYS @@ -79,48 +81,28 @@ //----------------------------------------------------------------------------- // Global control of cache +// This is all handled in assembly (see vectors.S) due to a requirement about +// not fiddling the cache from cachable memory. + +externC void cyg_hal_cache_enable(void); +externC void cyg_hal_cache_disable(void); +externC void cyg_hal_cache_invalidate_all(void); +externC void cyg_hal_cache_sync(void); +externC void cyg_hal_cache_write_mode(int mode); // Enable the cache -#define HAL_UCACHE_ENABLE() \ - CYG_MACRO_START \ - register cyg_uint32 __tmp; \ - HAL_READ_UINT32(CYGARC_REG_CCR, __tmp); \ - __tmp |= CYGARC_REG_CCR_CE; \ - HAL_WRITE_UINT32(CYGARC_REG_CCR, __tmp); \ - CYG_MACRO_END +#define HAL_UCACHE_ENABLE() cyg_hal_cache_enable() // Disable the cache -#define HAL_UCACHE_DISABLE() \ - CYG_MACRO_START \ - register cyg_uint32 __tmp; \ - HAL_READ_UINT32(CYGARC_REG_CCR, __tmp); \ - __tmp &= ~CYGARC_REG_CCR_CE; \ - HAL_WRITE_UINT32(CYGARC_REG_CCR, __tmp); \ - CYG_MACRO_END +#define HAL_UCACHE_DISABLE() cyg_hal_cache_disable() // Invalidate the entire cache -// Note: The CF bit does not cause any data to be written back before -// invalidation of the cache. -#define HAL_UCACHE_INVALIDATE_ALL() \ - CYG_MACRO_START \ - register cyg_uint32 __tmp; \ - HAL_READ_UINT32(CYGARC_REG_CCR, __tmp); \ - __tmp |= CYGARC_REG_CCR_CF; \ - HAL_WRITE_UINT32(CYGARC_REG_CCR, __tmp); \ - CYG_MACRO_END +#define HAL_UCACHE_INVALIDATE_ALL() cyg_hal_cache_invalidate_all() // Synchronize the contents of the cache with memory. -#define HAL_UCACHE_SYNC() \ - CYG_MACRO_START \ - register cyg_uint32* __p; \ - register cyg_uint32* __top = (cyg_uint32*)CYGARC_REG_CACHE_ADDRESS_TOP; \ - for (__p = (cyg_uint32*)CYGARC_REG_CACHE_ADDRESS_BASE; \ - __p < __top; \ - __p += CYGARC_REG_CACHE_ADDRESS_STEP/sizeof(cyg_uint32)) \ - *__p = CYGARC_REG_CACHE_ADDRESS_FLUSH; \ - CYG_MACRO_END +#define HAL_UCACHE_SYNC() cyg_hal_cache_sync() -// Query the state of the cache +// Query the state of the cache (does not affect the caching) #define HAL_UCACHE_IS_ENABLED(_state_) \ CYG_MACRO_START \ HAL_READ_UINT32(CYGARC_REG_CCR, (_state_)); \ @@ -131,15 +113,7 @@ //#define HAL_UCACHE_BURST_SIZE(_size_) // Set the cache write mode -#define HAL_UCACHE_WRITE_MODE( _mode_ ) \ - CYG_MACRO_START \ - register cyg_uint32 __tmp; \ - HAL_READ_UINT32(CYGARC_REG_CCR, __tmp); \ - __tmp &= ~CYGARC_REG_CCR_CB; \ - if (HAL_UCACHE_WRITEBACK_MODE == (_mode_)) \ - __tmp |= CYGARC_REG_CCR_CB; \ - HAL_WRITE_UINT32(CYGARC_REG_CCR, __tmp); \ - CYG_MACRO_END +#define HAL_UCACHE_WRITE_MODE( _mode_ ) cyg_hal_cache_write_mode(_mode_) #define HAL_UCACHE_WRITETHRU_MODE 0 #define HAL_UCACHE_WRITEBACK_MODE 1
--- a/packages/hal/sh/arch/current/include/hal_intr.h +++ b/packages/hal/sh/arch/current/include/hal_intr.h @@ -448,7 +448,6 @@ externC cyg_uint8 cyg_hal_ILVL_table[]; } \ CYG_MACRO_END - #define HAL_INTERRUPT_MASK( _vector_ ) \ CYG_MACRO_START \ switch( (_vector_) ) { \ @@ -491,10 +490,12 @@ externC cyg_uint8 cyg_hal_ILVL_table[]; } \ CYG_MACRO_END + #define HAL_INTERRUPT_ACKNOWLEDGE( _vector_ ) #define HAL_INTERRUPT_CONFIGURE( _vector_, _level_, _up_ ) + //-------------------------------------------------------------------------- // Clock control
--- a/packages/hal/sh/arch/current/src/hal_mk_defs.c +++ b/packages/hal/sh/arch/current/src/hal_mk_defs.c @@ -47,6 +47,7 @@ #include <cyg/hal/hal_arch.h> // HAL header #include <cyg/hal/hal_intr.h> // HAL header +#include <cyg/hal/hal_cache.h> // HAL header #ifdef CYGPKG_KERNEL # include <pkgconf/kernel.h> # include <cyg/kernel/instrmnt.h> @@ -103,6 +104,12 @@ main(void) DEFINE(CYGNUM_HAL_VSR_COUNT, CYGNUM_HAL_VSR_COUNT); DEFINE(CYGNUM_HAL_VSR_EXCEPTION_COUNT, CYGNUM_HAL_VSR_EXCEPTION_COUNT); + // Caching details + DEFINE(CYGARC_REG_CACHE_ADDRESS_FLUSH, CYGARC_REG_CACHE_ADDRESS_FLUSH); + DEFINE(CYGARC_REG_CACHE_ADDRESS_BASE,CYGARC_REG_CACHE_ADDRESS_BASE); + DEFINE(CYGARC_REG_CACHE_ADDRESS_TOP,CYGARC_REG_CACHE_ADDRESS_TOP); + DEFINE(CYGARC_REG_CACHE_ADDRESS_STEP,CYGARC_REG_CACHE_ADDRESS_STEP); + // Variant definitions - want these to be included instead. }
--- a/packages/hal/sh/arch/current/src/vectors.S +++ b/packages/hal/sh/arch/current/src/vectors.S @@ -39,7 +39,8 @@ ## vectors. It also contains the first level default VSRs ## that save and restore state for both exceptions and ## interrupts. -## +## Notes: The SH architecture files are still more SH3 specific than +## architecture neutral, hence the sub-variant configury. ######DESCRIPTIONEND#### ## ##========================================================================== @@ -494,6 +495,7 @@ 9: 1: #endif + #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR) mov #3,r7 #endif @@ -885,6 +887,121 @@ restore_state: #endif #--------------------------------------------------------------------------- +# Cache operations +# These need to be written in assembly to ensure they do not rely on data +# in cachable space (i.e., code must use registers exclusively, not the stack). + +# This macro must be used at the top of each cache function. It ensures +# that the code gets executed from a shadow region where caching is disabled +# (0xA0000000). + .macro GOTO_NONCACHED_SHADOW + mova 10f,r0 + mov.l $MASK,r1 + and r1,r0 + mov.l $BASE,r1 + or r1,r0 + jmp @r0 + nop + .align 2 +10: + .endm + + .globl _cyg_hal_cache_enable +_cyg_hal_cache_enable: + GOTO_NONCACHED_SHADOW + mov #CYGARC_REG_CCR,r1 + mov.l @r1,r0 + or #CYGARC_REG_CCR_CE,r0 + mov.l r0,@r1 + nop + rts + nop + + .globl _cyg_hal_cache_disable +_cyg_hal_cache_disable: + GOTO_NONCACHED_SHADOW + mov #CYGARC_REG_CCR,r1 + mov.l @r1,r0 + mov #CYGARC_REG_CCR_CE,r2 + not r2,r2 + and r2,r0 + mov.l r0,@r1 + nop + rts + nop + + .globl _cyg_hal_cache_invalidate_all +_cyg_hal_cache_invalidate_all: + GOTO_NONCACHED_SHADOW + mov #CYGARC_REG_CCR,r1 + mov.l @r1,r0 + or #CYGARC_REG_CCR_CF,r0 + mov.l r0,@r1 + nop ! Nothing in the docs suggest we need + nop ! nops here, but without them, the + nop ! CPU crashes. + rts + nop + + .globl _cyg_hal_cache_sync +_cyg_hal_cache_sync: + GOTO_NONCACHED_SHADOW + mov.l $CYGARC_REG_CACHE_ADDRESS_FLUSH,r0 + mov.l $CYGARC_REG_CACHE_ADDRESS_BASE,r1 + mov.l $CYGARC_REG_CACHE_ADDRESS_TOP,r2 + mov.l $CYGARC_REG_CACHE_ADDRESS_STEP,r3 +1: cmp/hi r1,r2 + bf 2f + mov.l r0,@r1 + bra 1b + add r3,r1 ! delay slot! +2: nop + rts + nop + + .globl _cyg_hal_cache_write_mode +_cyg_hal_cache_write_mode: + GOTO_NONCACHED_SHADOW + # Mode argument in r4. Compute the WT and CB states from this + mov r4,r0 + and #1,r0 + shll r0 ! shift to WT position + mov r0,r1 ! duplicate at CB position + shll r1 + or r1,r0 + xor #CYGARC_REG_CCR_WT,r0 ! WT must be 0 for write-back + # Read current state and mask out the two caching mode bits + mov #CYGARC_REG_CCR,r1 + mov.l @r1,r3 + mov #CYGARC_REG_CCR_CB|CYGARC_REG_CCR_WT,r2 + not r2,r2 + and r2,r3 + # Or in the new settings and restore to CCR + or r0,r3 + mov.l r3,@r1 + nop + rts + nop + + + + .align 2 +$CYGARC_REG_CACHE_ADDRESS_FLUSH: + .long CYGARC_REG_CACHE_ADDRESS_FLUSH +$CYGARC_REG_CACHE_ADDRESS_BASE: + .long CYGARC_REG_CACHE_ADDRESS_BASE +$CYGARC_REG_CACHE_ADDRESS_TOP: + .long CYGARC_REG_CACHE_ADDRESS_TOP +$CYGARC_REG_CACHE_ADDRESS_STEP: + .long CYGARC_REG_CACHE_ADDRESS_STEP + + +$MASK: + .long 0x1fffffff ! mask off top 3 bits +$BASE: + .long 0xa0000000 ! base of non-cachable memory + +#--------------------------------------------------------------------------- # Interrupt vector tables. # These tables contain the isr, data and object pointers used to deliver # interrupts to user code.
--- a/packages/io/serial/current/ChangeLog +++ b/packages/io/serial/current/ChangeLog @@ -1,3 +1,7 @@ +2000-04-17 Hugo Tyson <hmt@cygnus.co.uk> + + * src/PKGconf.mak: remove; it's obsolete. + 2000-04-13 Gary Thomas <gthomas@redhat.com> * src/common/serial.c (serial_write): Make safer - only call
--- a/packages/io/wallclock/current/ChangeLog +++ b/packages/io/wallclock/current/ChangeLog @@ -1,3 +1,8 @@ +2000-04-19 Jesper Skov <jskov@cygnus.co.uk> + + * src/wallclock.cxx: Construct after kernel RTC since the + emulation implementation may have to use the RTC. + 2000-04-13 Jesper Skov <jskov@redhat.com> * tests/wallclock.cxx: Use TEST_NA if N/A.
--- a/packages/io/wallclock/current/src/wallclock.cxx +++ b/packages/io/wallclock/current/src/wallclock.cxx @@ -72,7 +72,7 @@ //----------------------------------------------------------------------------- // Local static variables -static Cyg_WallClock wallclock_instance CYG_INIT_PRIORITY( CLOCK ); +static Cyg_WallClock wallclock_instance CYGBLD_ATTRIB_INIT_AFTER( CYG_INIT_CLOCK ); #ifndef CYGSEM_WALLCLOCK_SET_GET_MODE static cyg_uint32 epoch_ticks;
--- a/packages/kernel/current/ChangeLog +++ b/packages/kernel/current/ChangeLog @@ -1,3 +1,17 @@ +2000-04-26 Jesper Skov <jskov@redhat.com> + + * tests/kcache1.c: Also to flush testing with unified caches. + +2000-04-25 Jesper Skov <jskov@redhat.com> + + * tests/kcache1.c: Fixed cache check to also look for unified + caches. + +2000-04-12 Gary Thomas <gthomas@redhat.com> + + * src/common/kapi.cxx (cyg_scheduler_safe_lock): + * include/kapi.h: Add 'cyg_scheduler_safe_lock()' function. + 2000-04-12 Jesper Skov <jskov@redhat.com> * cdl/interrupts.cdl:
--- a/packages/kernel/current/include/kapi.h +++ b/packages/kernel/current/include/kapi.h @@ -127,6 +127,11 @@ void cyg_scheduler_start(void) __attribu void cyg_scheduler_lock(void); void cyg_scheduler_unlock(void); + +/* Just like 'cyg_scheduler_lock()', but never take the lock higher than 1 */ +/* Thus this call is safe even if the scheduler is already locked and a */ +/* subsequent call to 'cyg_scheduler_unlock()' will completely unlock. */ +void cyg_scheduler_safe_lock(void); /*---------------------------------------------------------------------------*/ /* Thread operations */
--- a/packages/kernel/current/src/common/kapi.cxx +++ b/packages/kernel/current/src/common/kapi.cxx @@ -115,6 +115,18 @@ externC void cyg_scheduler_lock(void) "Scheduler overlocked" ); } +/* Lock the scheduler, but never more than level=1. */ +externC void cyg_scheduler_safe_lock(void) +{ + Cyg_Scheduler::lock(); + cyg_ucount32 slock = Cyg_Scheduler::get_sched_lock(); + if (slock > 1) + Cyg_Scheduler::unlock(); + // get_sched_lock() is unsigned, see below "cyg_ucount32 lock" + CYG_ASSERT( (0xff000000 & (Cyg_Scheduler::get_sched_lock())) == 0, + "Scheduler overlocked" ); +} + /* Unlock the scheduler. */ externC void cyg_scheduler_unlock(void) {
--- a/packages/kernel/current/tests/clockcnv.cxx +++ b/packages/kernel/current/tests/clockcnv.cxx @@ -166,6 +166,8 @@ static void entry0( CYG_ADDRWORD data ) if (cyg_test_is_simulator) j += 30; // test fewer values /* tr.b..m..k.. */ + + for ( delay = j; delay < 1000000000000ll; delay *= 10 ) { // get the converted result cyg_uint64 result = Cyg_Clock::convert( delay, &cv );
--- a/packages/kernel/current/tests/kcache1.c +++ b/packages/kernel/current/tests/kcache1.c @@ -43,12 +43,13 @@ #include <cyg/infra/testcase.h> -#ifdef HAL_DCACHE_SIZE +#include <cyg/hal/hal_cache.h> + +#if defined(HAL_DCACHE_SIZE) || defined(HAL_UCACHE_SIZE) #ifdef CYGVAR_KERNEL_COUNTERS_CLOCK #ifdef CYGFUN_KERNEL_API_C #include <cyg/infra/diag.h> -#include <cyg/hal/hal_cache.h> #include <cyg/hal/hal_intr.h> // ------------------------------------------------------------------------- @@ -175,7 +176,8 @@ void time1II(void) static void time0DI(register cyg_uint32 stride) { register cyg_uint32 j,k; - cyg_tick_count_t count0, count1; + volatile cyg_tick_count_t count0; + cyg_tick_count_t count1; cyg_ucount32 t; register char c; @@ -217,7 +219,7 @@ void time1DI(void) static void entry0( cyg_addrword_t data ) { register CYG_INTERRUPT_STATE oldints; - + #ifdef HAL_CACHE_UNIFIED HAL_DISABLE_INTERRUPTS(oldints); @@ -236,6 +238,16 @@ static void entry0( cyg_addrword_t data CYG_TEST_INFO("Cache on"); time1(); +#ifdef HAL_DCACHE_INVALIDATE_ALL + HAL_DISABLE_INTERRUPTS(oldints); + HAL_DCACHE_PURGE_ALL(); + HAL_UCACHE_INVALIDATE_ALL(); + HAL_UCACHE_ENABLE(); + HAL_RESTORE_INTERRUPTS(oldints); + CYG_TEST_INFO("Cache on: invalidate Cache (expect bogus times)"); + time1DI(); +#endif + #else // HAL_CACHE_UNIFIED HAL_DISABLE_INTERRUPTS(oldints); @@ -313,8 +325,7 @@ static void entry0( cyg_addrword_t data CYG_TEST_PASS_FINISH("End of test"); cyg_test_is_simulator = 1; -#endif - +#endif #ifdef HAL_ICACHE_INVALIDATE_ALL HAL_DISABLE_INTERRUPTS(oldints); HAL_DCACHE_PURGE_ALL();
