dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / lib / ppu / FastCommunication.cpp
1 /*
2  * FastCommunication.cpp / Version PPE
3  *
4  *  Created on: Mar 3, 2009
5  *      Author: lschor
6  *
7  * For remarks to this file, please refer to the SPE variant.
8  *
9  * Completion of the SPEs:
10  * Is coordinated by this process. Each SPE has to send a request to
11  * the PPE if it is allowed to finish.
12  * If all SPEs have requested to complete, the PPE sends to the SPEs a
13  * message that they can complete, thus return.
14  */
15
16 #include "FastCommunication.h"
17
18 /*
19  * Constructor
20  */
21 FastCommunication::FastCommunication(int nrOfQueues,
22                 uint64_t *context_all, uint64_t * ea_ls_base,
23                 int32_t * queueFromSPEIn, int32_t * queueOnSPEIn,
24                 uint64_t *fifoTails) {
25
26         _context_all = context_all;
27         queueFromSPE = queueFromSPEIn;
28         queueOnSPE = queueOnSPEIn;
29         _ea_ls_base = ea_ls_base;
30         _fifoTails = fifoTails;
31         _nrSpeComplete = 0;
32
33         _nrOfQueues = nrOfQueues;
34         try { _fifos = new fifoCollection[nrOfQueues]; }
35         catch(std::bad_alloc &e) {
36             fprintf(stderr, "[FastCommunication] Memory allocation failure\n");
37             exit(1);
38         }
39
40         for (int i = 0; i < MAXNOREQ; i++) {
41                 _request[i].valid = false;
42         }
43 }
44
45 /*
46  * Deconstructor
47  */
48 FastCommunication::~FastCommunication() {
49         delete _fifos;
50 }
51
52 /*
53  * Register an additional FIFO in the Communication
54  */
55 bool FastCommunication::addFifo(int fifoNr, Fifo* fifo, int type,
56                 int queue) {
57         _fifos[fifoNr].fifo = fifo;
58         _fifos[fifoNr].queue = queue;
59         _fifos[fifoNr].type = type;
60         _fifos[fifoNr].iswfifo = false;
61
62         // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them
63         if (_nrOfRequest < MAXNOREQ) {
64                 _nrOfRequest += 2;
65         }
66
67         return true;
68 }
69
70 /*
71  * Register an additional WindowedFIFO in the Communication
72  */
73 bool FastCommunication::addWFifo(int fifoNr, WindowedFifo* wfifo,
74                 int type, int queue) {
75         _fifos[fifoNr].wfifo = wfifo;
76         _fifos[fifoNr].queue = queue;
77         _fifos[fifoNr].type = type;
78         _fifos[fifoNr].iswfifo = true;
79
80         // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them
81         if (_nrOfRequest < MAXNOREQ) {
82                 _nrOfRequest += 2;
83         }
84
85         return true;
86 }
87
88 /*
89  * Communication: Main update procedure to update
90  */
91 bool FastCommunication::update() {
92         // Check if you have received a new message
93         for (int processNr = 0; processNr < NUM_SPES; processNr++) {
94                 if (!spe_out_mbox_status((spe_context*) _context_all[processNr]))
95                         continue;
96
97                 uint32_t messageIn;
98                 spe_out_mbox_read((spe_context*) _context_all[processNr],
99                                 &messageIn, 1);
100
101                 uint32_t code = GETFASTCODE(messageIn);
102                 uint32_t queue = GETFASTQUEUE(messageIn);
103                 uint32_t len = GETFASTLEN(messageIn);
104
105                 /***************************************************************************************************************/
106                 if (code == SPE_READ_DEMAND) // Have to send a write address (1) --> (2)
107                 {
108                         // Find out for which fifo the request is
109                         fifoCollection *fifocol = NULL;
110                         int i;
111                         for (i = 0; i < _nrOfQueues; i++) {
112                                 if (_fifos[i].queue == queue) {
113                                         fifocol = &_fifos[i];
114                                         break;
115                                 }
116                         }
117
118                         // The queue was not found
119                         if (fifocol == NULL) {
120                                 printf("PPU COM> ERROR, this queue does not exists!\n");
121                                 return false;
122                         }
123
124                         // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125                         // Windowed FIFO
126                         if (_fifos[i].iswfifo) {
127                                 WindowedFifo* wfifo = NULL;
128                                 wfifo = _fifos[i].wfifo;
129
130                                 uint32_t inTail = wfifo->_inTail;
131
132                                 // This is the len we like to read
133                                 len = len > (wfifo->unused()) ? wfifo->unused() : len;
134
135                                 // We can read something
136                                 if (len > 0) {
137                                         // Write all information we used to the request-memory
138                                         comRequest* request = newRequest();
139
140                                         // Has no memory to store a new request
141                                         if (request == NULL) {
142                                                 // not possible to start a request for this SPE --> Send len = 0
143                                                 uint32_t message = CREATEFASTMESSAGE(
144                                                                 SPE_READ_COMPLETE, queue, 0);
145                                                 sendMessage(message, queueFromSPE[queue]);
146                                                 return false;
147                                         }
148
149                                         uint64_t baseAddress = _fifoTails[queue] + inTail;
150                                         while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
151                                                 baseAddress--;
152
153                                         // Offset
154                                         uint32_t offset = _fifoTails[queue] + inTail
155                                                         - baseAddress;
156
157                                         // Store all data in the request buffer
158                                         request->data = (char *) _malloc_align(roundDMA(len
159                                                         + offset), ALIGNMENT_FACTOR);
160                                         request->len = len;
161                                         request->wfifo = wfifo;
162                                         request->iswfifo = true;
163                                         request->status = read_started;
164                                         request->queue = queue;
165                                         request->offset = offset;
166
167                                         int ret;
168                                         do {
169                                                 ret = spe_mfcio_put(
170                                                                 (spe_context*) _context_all[processNr],
171                                                                 baseAddress, (void *) &(request->data[0]),
172                                                                 roundDMA(len + offset), request->tag_id,
173                                                                 0, 0);
174                                         } while (ret != 0);
175                                 } else {
176 #ifndef STORE_REQUESTS                // Send len = 0 back to the sender, this one should try it in a later phase
177                                         uint32_t message = CREATEFASTMESSAGE(
178                                                         SPE_READ_COMPLETE, queue, 0);
179                                         sendMessage(message, queueFromSPE[queue]);
180 #else                                // I store the request and may try in a later time to start the transfer
181                                         comRequest* request = newRequest();
182
183                                         // Has no memory to store a new request
184                                         if (request == NULL)
185                                         {
186                                                 // not possible to start a request for this SPE --> Send len = 0
187                                                 uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0);
188                                                 sendMessage(message, queueFromSPE[queue]);
189                                                 return false;
190                                         }
191
192                                         request->len = len;
193                                         request->wfifo = wfifo;
194                                         request->iswfifo = true;
195                                         request->status = read_pending;
196                                         request->queue = queue;
197 #endif
198                                 }
199
200                         }
201
202                         // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203                         // Classic FIFO
204                         else {
205                                 Fifo* fifo = NULL;
206                                 fifo = _fifos[i].fifo;
207
208                                 uint32_t inTail = fifo->_inTail;
209
210                                 // This is the len we like to read
211                                 len = len > (fifo->unused()) ? fifo->unused() : len;
212
213                                 // We can read something
214                                 if (len > 0) {
215                                         // Write all information we used to the request-memory
216                                         comRequest* request = newRequest();
217
218                                         // Has no memory to store a new request
219                                         if (request == NULL) {
220                                                 // not possible to start a request for this SPE --> Send len = 0
221                                                 uint32_t message = CREATEFASTMESSAGE(
222                                                                 SPE_READ_COMPLETE, queue, 0);
223                                                 sendMessage(message, queueFromSPE[queue]);
224                                                 return false;
225                                         }
226
227                                         uint64_t baseAddress = _fifoTails[queue] + inTail;
228                                         while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
229                                                 baseAddress--;
230
231                                         // Offset
232                                         uint32_t offset = _fifoTails[queue] + inTail
233                                                         - baseAddress;
234
235                                         // Store all data in the request buffer
236                                         request->data = (char *) _malloc_align(roundDMA(len
237                                                         + offset), ALIGNMENT_FACTOR);
238                                         request->len = len;
239                                         request->fifo = fifo;
240                                         request->iswfifo = false;
241                                         request->status = read_started;
242                                         request->queue = queue;
243                                         request->offset = offset;
244
245                                         int ret;
246                                         do {
247                                                 ret = spe_mfcio_put(
248                                                                 (spe_context*) _context_all[processNr],
249                                                                 baseAddress, (void *) &(request->data[0]),
250                                                                 roundDMA(len + offset), request->tag_id,
251                                                                 0, 0);
252                                         } while (ret != 0);
253                                 }
254
255                                 // Len == 0
256                                 else {
257 #ifndef STORE_REQUESTS                // Send len = 0 back to the sender, this one should try it in a later phase
258                                         uint32_t message = CREATEFASTMESSAGE(
259                                                         SPE_READ_COMPLETE, queue, 0);
260                                         sendMessage(message, queueFromSPE[queue]);
261 #else                                // I store the request and may try in a later time to start the transfer
262                                         comRequest* request = newRequest();
263
264                                         // Has no memory to store a new request
265                                         if (request == NULL) {
266                                                 // not possible to start a request for this SPE --> Send len = 0
267                                                 uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0);
268                                                 sendMessage(message, queueFromSPE[queue]);
269                                                 return false;
270                                         }
271
272                                         request->len = len;
273                                         request->fifo = fifo;
274                                         request->iswfifo = false;
275                                         request->status = read_pending;
276                                         request->queue = queue;
277 #endif
278                                 }
279                         }
280                 }
281
282                 /***************************************************************************************************************/
283                 else if (code == SPE_READ_COMPLETE) // Can finish a write request (4) --> (5)
284                 {
285                         // Get the stored request
286                         comRequest* request = getRequest(read_request_sent, queue);
287
288                         if (request == NULL) {
289                                 printf("PPU Communicate> Couldn't find the request\n");
290                                 return 0;
291                         }
292
293                         // Inform my FIFO that the request is completed
294                         if (request->iswfifo)
295                                 request->wfifo->dmaRead(len);
296                         else
297                                 request->fifo->dmaRead(len);
298
299                         // Request free
300                         deleteRequest(request);
301                 }
302
303                 /***************************************************************************************************************/
304                 else if (code == SPE_COMPLETE) // One SPE has finished
305                 {
306                         _nrSpeComplete++;
307                 }
308         }
309
310         /***************************************************************************************************************/
311         // Check if some active write processes have finished (4)
312         uint8_t req = _currentRequest;
313
314         for (int i = 0; i < _nrOfRequest; i++) {
315                 if (_request[req].valid) {
316                         if (_request[req].status == read_started) {
317                                 if (!(testMessage(queueFromSPE[_request[req].queue]) > 0))
318                                         continue;
319
320                                 uint32_t tag_id = _request[req].tag_id;
321                                 uint32_t ret;
322                                 uint32_t
323                                                 test =
324                                                                 spe_mfcio_tag_status_read(
325                                                                                 (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
326                                                                                 0, SPE_TAG_IMMEDIATE, &ret);
327
328                                 if (((ret & (1 << tag_id)) == 0)) {
329                                         // Have to write the data into the fifo
330                                         if (_request[req].iswfifo) { // WFIFO
331
332                                                 _request[req].wfifo->dmaWrite(
333                                                                 (char *) _request[req].data
334                                                                                 + _request[req].offset,
335                                                                 _request[req].len);
336                                                 _free_align(_request[req].data);
337
338                                                 // Increase the inTail value (used to know where the last request was started)
339
340                                                 _request[req].wfifo->_inTail
341                                                                 = (_request[req].wfifo->_inTail
342                                                                                 + _request[req].len) % (FIFO_SIZE[_request[req].queue]);
343                                         } else { // FIFO
344                                                 _request[req].fifo->write(
345                                                                 (char *) _request[req].data
346                                                                                 + _request[req].offset,
347                                                                 _request[req].len);
348                                                 _free_align(_request[req].data);
349
350                                                 _request[req].fifo->_inTail
351                                                                 = (_request[req].fifo->_inTail
352                                                                                 + _request[req].len) % (FIFO_SIZE[_request[req].queue]);
353
354                                         }
355
356                                         uint32_t message = CREATEFASTMESSAGE(
357                                                         SPE_READ_COMPLETE, _request[req].queue,
358                                                         _request[req].len);
359                                         sendMessage(message, queueFromSPE[_request[req].queue]);
360
361                                         deleteRequest(&_request[req]);
362                                         _currentRequest = (req + 1) % _nrOfRequest;
363
364                                         break;
365                                 }
366                         } else if (_request[req].status == read_pending) { // Has an open request for sending
367
368                                 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369                                 // Windowed FIFO
370                                 if (_request[req].iswfifo) {
371
372                                         if (_request[req].wfifo->unused() > 0) {
373                                                 comRequest *request = &_request[req];
374
375                                                 // This is the len we like to read
376                                                 uint32_t len = request->len > (request->wfifo->unused()) ? request->wfifo->unused()
377                                                                 : request->len;
378
379                                                 uint32_t inTail = request->wfifo->_inTail;
380                                                 uint64_t baseAddress = _fifoTails[request->queue]
381                                                                 + inTail;
382
383                                                 while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
384                                                         baseAddress--;
385
386                                                 // Offset --> How much we had to align
387                                                 uint32_t offset = _fifoTails[request->queue]
388                                                                 + inTail - baseAddress;
389
390                                                 request->data = (char *) _malloc_align(roundDMA(
391                                                                 len + offset), ALIGNMENT_FACTOR);
392                                                 request->len = len;
393                                                 request->status = read_started;
394                                                 request->offset = offset;
395
396                                                 // Set up the request in the MFC
397                                                 int ret;
398                                                 do {
399                                                         ret = spe_mfcio_put(
400                                                                         (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
401                                                                         baseAddress,
402                                                                         (void *) &(request->data[0]),
403                                                                         roundDMA(len + offset),
404                                                                         request->tag_id, 0, 0);
405                                                 } while (ret != 0);
406                                         }
407                                 }
408
409                                 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410                                 // Classic FIFO
411                                 else {
412
413                                         if (_request[req].fifo->unused() > 0) {
414                                                 comRequest *request = &_request[req];
415
416                                                 // This is the len we like to read
417                                                 uint32_t len =  request->len > (request->fifo->unused()) ? request->fifo->unused() : request->len;
418
419                                                 uint32_t inTail = request->fifo->_inTail;
420                                                 uint64_t baseAddress = _fifoTails[request->queue]
421                                                                 + inTail;
422
423                                                 while (baseAddress % 16 != 0)
424                                                         baseAddress--;
425
426                                                 // Offset
427                                                 uint32_t offset = _fifoTails[request->queue]
428                                                                 + inTail - baseAddress;
429
430                                                 // Store all data in the request buffer
431                                                 request->data = (char *) _malloc_align(roundDMA(
432                                                                 len + offset), ALIGNMENT_FACTOR);
433                                                 request->len = len;
434                                                 request->status = read_started;
435                                                 request->offset = offset;
436
437                                                 // Start the DMA transfer
438                                                 int ret;
439                                                 do {
440                                                         ret
441                                                                         = spe_mfcio_put(
442                                                                                         (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
443                                                                                         baseAddress,
444                                                                                         (void *) &(request->data[0]),
445                                                                                         roundDMA(len + offset),
446                                                                                         request->tag_id, 0, 0);
447                                                 } while (ret != 0);
448                                         }
449                                 }
450                         }
451                 }
452                 req = (req + 1) % _nrOfRequest;
453         }
454
455         /***************************************************************************************************************/
456         // Have some out - queue some data to send
457         for (int i = 0; i < _nrOfQueues; i++) {
458                 if (_fifos[i].type == this->out) {
459                         if (_fifos[i].iswfifo) { // WFIFO
460                                 // Start only a write process if there is really enough place in the outbound mailbox
461                                 if (_fifos[i].wfifo->dmaAllowed()
462                                                 && _fifos[i].wfifo->used() > 0) {
463                                         uint32_t queue = _fifos[i].queue;
464
465                                         // Can we send a message to this processor or is it blocked?
466                                         if (testMessage(queueOnSPE[queue]) <= 0) {
467                                                 continue;
468                                         }
469
470                                         // Write all information we used to the request-memory
471                                         comRequest* request = newRequest();
472
473                                         // Has no memory to store a new request
474                                         if (request == NULL) {
475                                         } else {
476                                                 uint32_t len = _fifos[i].wfifo->dmaStart();
477                                                 // Create a write-demand message
478                                                 uint32_t message = CREATEFASTMESSAGE(
479                                                                 SPE_READ_DEMAND, queue, len);
480
481                                                 request->len = len;
482                                                 request->queue = queue;
483                                                 request->status = read_request_sent;
484                                                 request->wfifo = _fifos[i].wfifo;
485                                                 request->iswfifo = true;
486
487                                                 sendMessage(message, queueOnSPE[queue]);
488                                         }
489                                         break;
490                                 }
491                         } else { // FIFO
492                                 // Start only a write process if there is really enough place in the outbound mailbox
493                                 if (_fifos[i].fifo->dmaAllowed() && _fifos[i].fifo->used()
494                                                 > 0) {
495                                         uint32_t queue = _fifos[i].queue;
496
497                                         if (testMessage(queueOnSPE[queue]) <= 0)
498                                                 continue;
499
500                                         // Write all information we used to the request-memory
501                                         comRequest* request = newRequest();
502
503                                         // Has no memory to store a new request
504                                         if (request == NULL) {
505                                         } else {
506                                                 uint32_t len = _fifos[i].fifo->dmaStart();
507                                                 uint32_t message = CREATEFASTMESSAGE(
508                                                                 SPE_READ_DEMAND, queue, len);
509                                                 request->len = len;
510                                                 request->queue = queue;
511                                                 request->status = read_request_sent;
512                                                 request->fifo = _fifos[i].fifo;
513                                                 request->iswfifo = false;
514
515                                                 sendMessage(message, queueOnSPE[queue]);
516                                         }
517                                         break;
518                                 }
519                         }
520                 }
521         }
522         return true;
523 }
524
525 /*
526  * Create a new request to store in the cache
527  *
528  */
529 comRequest* FastCommunication::newRequest() {
530         for (int i = 0; i < _nrOfRequest; i++) {
531                 if (!_request[i].valid) {
532                         _request[i].tag_id = i + 3;
533                         _request[i].valid = true;
534                         return &(_request[i]);
535                 }
536         }
537
538         return NULL;
539 }
540
541 /*
542  * Delete the request
543  *
544  */
545 void FastCommunication::deleteRequest(comRequest* request) {
546         request->valid = false;
547         request->tag_id = 0;
548 }
549
550 /*
551  * Returns the request one like to get
552  */
553 comRequest* FastCommunication::getRequest(uint8_t status, uint32_t queue) {
554         uint8_t req = _currentRequest;
555
556         for (int i = 0; i < _nrOfRequest; i++) {
557                 if (_request[req].valid && _request[req].status == status
558                                 && _request[req].queue == queue) {
559                         _currentRequest = (req + 1) % _nrOfRequest;
560                         return &(_request[req]);
561                 }
562                 req = (req + 1) % _nrOfRequest;
563         }
564
565         return NULL;
566 }
567
568 /**
569  * True if no communication is necessary, false if there is active communication
570  */
571 bool FastCommunication::empty() { /////////////////////////////////////////////////////////////////
572         // check if one fifo would like to send something to another SPE
573         for (int i = 0; i < _nrOfQueues; i++) {
574                 if (_fifos[i].type == this->out) {
575                         if (_fifos[i].iswfifo) { // WFIFO
576                                 if (_fifos[i].wfifo->used() > 0) 
577                                 {
578                                         return false;
579                                 }
580                         } else {
581                                 if (_fifos[i].fifo->used() > 0) 
582                                 {
583                                         return false;
584                                 }               
585                         }
586                 }
587         }
588
589         // are open sendings?
590         for (int i = 0; i < _nrOfRequest; i++) {
591                 if (_request[i].valid) {
592                         return false;
593                 }
594         }
595
596         if (_nrSpeComplete < NUM_SPES) {
597                 return false;
598         }
599
600         return true;
601 }
602
603 /**
604  * Send a message to a SPE
605  */
606 void FastCommunication::sendMessage(uint32_t message, int32_t process) {
607         spe_in_mbox_write((spe_context*) _context_all[process],
608                         (uint32_t*) &message, 1, SPE_MBOX_ANY_NONBLOCKING);
609 }
610
611 /**
612  * Test if we can send a message to an SPE without stalling
613  */
614 int FastCommunication::testMessage(int32_t process) {
615         return spe_in_mbox_status((spe_context*) _context_all[process]);
616 }
617