1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_DriverCommandManager.cpp
4
5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Revision: 22289 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17 #include <nw/snd/snd_DriverCommandManager.h>
18
19 namespace nw {
20 namespace snd {
21 namespace internal {
22
GetInstance()23 DriverCommandManager& DriverCommandManager::GetInstance()
24 {
25 static DriverCommandManager instance;
26 return instance;
27 }
28
GetInstanceForTaskThread()29 DriverCommandManager& DriverCommandManager::GetInstanceForTaskThread()
30 {
31 static DriverCommandManager instance;
32 return instance;
33 }
34
DriverCommandManager()35 DriverCommandManager::DriverCommandManager()
36 {
37 }
38
Initialize(void * commandBuffer,u32 commandBufferSize)39 void DriverCommandManager::Initialize( void* commandBuffer, u32 commandBufferSize )
40 {
41 m_CommandListBegin = NULL;
42 m_CommandListEnd = NULL;
43
44 m_CommandTag = 0;
45
46 m_CommandMemoryAreaBegin = 0;
47 m_CommandMemoryAreaEnd = 0;
48 m_CommandMemoryAreaZeroFlag = false;
49
50 m_CommandMemoryArea = static_cast<u32*>(commandBuffer);
51 m_CommandMemoryAreaSize = commandBufferSize / sizeof(m_CommandMemoryArea[0]);
52
53 m_SendCommandQueue.Initialize( m_SendCommandQueueBuffer, COMMAND_QUEUE_SIZE );
54 m_RecvCommandQueue.Initialize( m_RecvCommandQueueBuffer, COMMAND_QUEUE_SIZE );
55 }
56
Finalize()57 void DriverCommandManager::Finalize()
58 {
59 m_SendCommandQueue.Finalize();
60 m_RecvCommandQueue.Finalize();
61 }
62
AllocMemory(u32 count)63 void* DriverCommandManager::AllocMemory( u32 count )
64 {
65 NW_ASSERT( count <= m_CommandMemoryAreaSize );
66
67 void* ptr = TryAllocMemory( count );
68 if ( ptr != NULL ) return ptr;
69
70 RecvCommandReply();
71 ptr = TryAllocMemory( count );
72 if ( ptr != NULL ) return ptr;
73
74 // 強制フラッシュ
75 while( ptr == NULL )
76 {
77 u32 tag = FlushCommand( true );
78 WaitCommandReply( tag );
79 ptr = TryAllocMemory( count );
80 }
81
82 return ptr;
83 }
84
TryAllocMemory(u32 count)85 void* DriverCommandManager::TryAllocMemory( u32 count )
86 {
87 void* ptr = NULL;
88
89 if ( m_CommandMemoryAreaZeroFlag ) return NULL;
90
91 if ( m_CommandMemoryAreaEnd > m_CommandMemoryAreaBegin ) {
92 // 連続領域の場合
93 if ( m_CommandMemoryAreaBegin + count <= m_CommandMemoryAreaEnd ) {
94 ptr = &m_CommandMemoryArea[m_CommandMemoryAreaBegin];
95 m_CommandMemoryAreaBegin += count;
96 }
97 }
98 else {
99 // 非連続領域の場合
100 if ( m_CommandMemoryAreaBegin + count <= m_CommandMemoryAreaSize ) {
101 ptr = &m_CommandMemoryArea[m_CommandMemoryAreaBegin];
102 m_CommandMemoryAreaBegin += count;
103 }
104 else if ( count <= m_CommandMemoryAreaEnd ) {
105 ptr = &m_CommandMemoryArea[0];
106 m_CommandMemoryAreaBegin = count;
107 }
108 }
109
110 if ( ptr != NULL && m_CommandMemoryAreaBegin == m_CommandMemoryAreaEnd ) {
111 m_CommandMemoryAreaZeroFlag = true;
112 }
113 return ptr;
114 }
115
GetAllocatableCommandSize() const116 u32 DriverCommandManager::GetAllocatableCommandSize() const
117 {
118 if ( m_CommandMemoryAreaZeroFlag ) return 0;
119
120 if ( m_CommandMemoryAreaEnd > m_CommandMemoryAreaBegin ) {
121 // 連続領域の場合
122 return m_CommandMemoryAreaEnd - m_CommandMemoryAreaBegin;
123 }
124 else {
125 // 非連続領域の場合
126 return ut::Max(
127 m_CommandMemoryAreaSize - m_CommandMemoryAreaBegin,
128 m_CommandMemoryAreaEnd
129 );
130 }
131 }
132
PushCommand(DriverCommand * command)133 u32 DriverCommandManager::PushCommand( DriverCommand* command )
134 {
135 if ( m_CommandListEnd == NULL )
136 {
137 m_CommandListBegin = command;
138 m_CommandListEnd = command;
139 }
140 else
141 {
142 m_CommandListEnd->next = command;
143 m_CommandListEnd = command;
144 }
145
146 command->next = NULL;
147
148 return m_CommandTag;
149 }
150
151 //---------------------------------------------------------------------------
152 //! @brief コマンドをフラッシュします。
153 //!
154 //! forceFlagがtrueの時は、必ず処理を行います。
155 //! コマンドが1つも登録されていない場合は、ダミーのコマンドを発行します。
156 //! 受信側の処理が滞っている場合は、空くまで待ちます。
157 //!
158 //! forceFlagがfalseの時は、必要以上の処理は行いません。
159 //! コマンドが1つも登録されていない場合は、何もせずに返ります。
160 //! 受信側の処理が滞っている場合も、何もせずに返ります。
161 //! 何もせずに返った場合、返り値は0(無効値)になることに注意してください。
162 //!
163 //! @param[in] forceFlag フラッシュ処理を強制するかどうかのフラグです。
164 //!
165 //! @return コマンドタグを返します。
166 //! ただし、forceFlagがfalseの時に、コマンドフラッシュが
167 //! 行われない場合は、0(無効値)を返します。
168 //!
169 //---------------------------------------------------------------------------
FlushCommand(bool forceFlag)170 u32 DriverCommandManager::FlushCommand( bool forceFlag )
171 {
172 if ( m_CommandListBegin == NULL ) {
173 if ( ! forceFlag ) return 0;
174
175 // ダミーコマンド発行
176 DriverCommand* command = AllocCommand<DriverCommand>();
177 command->id = DRIVER_COMMAND_DUMMY;
178 PushCommand(command);
179 }
180
181 uptr msg = reinterpret_cast<uptr>(m_CommandListBegin);
182 u32 tag = m_CommandTag;
183
184 nn::os::DataMemoryBarrier();
185
186 if ( forceFlag )
187 {
188 m_SendCommandQueue.Enqueue( msg );
189 }
190 else
191 {
192 if ( ! m_SendCommandQueue.TryEnqueue( msg ) ) {
193 return 0;
194 }
195 }
196
197 m_CommandListBegin->tag = tag;
198 m_CommandTag++;
199
200 m_CommandListBegin = NULL;
201 m_CommandListEnd = NULL;
202
203 return tag;
204 }
205
FinalizeCommandList(DriverCommand * commandList)206 void DriverCommandManager::FinalizeCommandList( DriverCommand* commandList )
207 {
208 m_FinishCommandTag = commandList->tag;
209
210 DriverCommand* command = commandList;
211
212 while( command != NULL )
213 {
214 if ( command->next == NULL ) {
215 // コマンドメモリの解放
216 m_CommandMemoryAreaEnd = command->memory_next;
217 m_CommandMemoryAreaZeroFlag = false;
218 if ( m_CommandMemoryAreaBegin == m_CommandMemoryAreaEnd ) {
219 // メモリの分断化を解消
220 m_CommandMemoryAreaBegin = m_CommandMemoryAreaEnd = 0;
221 }
222 break;
223 }
224
225 command = command->next;
226 }
227 }
228
IsFinishCommand(u32 tag) const229 bool DriverCommandManager::IsFinishCommand( u32 tag ) const
230 {
231 static const u32 limit = (1 << ((sizeof(tag) * 8)-2) );
232
233 if ( tag < m_FinishCommandTag )
234 {
235 return ( m_FinishCommandTag - tag < limit );
236 }
237 else
238 {
239 return ( tag - m_FinishCommandTag < limit );
240 }
241 }
242
RecvCommandReply()243 void DriverCommandManager::RecvCommandReply()
244 {
245 uptr msg;
246 while( m_RecvCommandQueue.TryDequeue( &msg ) )
247 {
248 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
249 FinalizeCommandList( commandList );
250 }
251 }
252
WaitCommandReply(u32 tag)253 void DriverCommandManager::WaitCommandReply( u32 tag )
254 {
255 while( true ) {
256 uptr msg = m_RecvCommandQueue.Dequeue();
257 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
258 FinalizeCommandList( commandList );
259
260 if ( tag == commandList->tag ) break;
261 }
262 }
263
ProcessCommand()264 void DriverCommandManager::ProcessCommand()
265 {
266 uptr msg;
267 while( m_SendCommandQueue.TryDequeue( &msg ) )
268 {
269 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
270
271 DriverCommand::ProcessCommandList( commandList );
272
273 nn::os::DataMemoryBarrier();
274
275 m_RecvCommandQueue.Enqueue( msg );
276 }
277 }
278
279 } // namespace nw::snd::internal
280 } // namespace nw::snd
281 } // namespace nw
282