gem5 [DEVELOP-FOR-25.1]
Loading...
Searching...
No Matches
ufs_device.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
61
69
70#include "dev/arm/ufs_device.hh"
71
72#include "params/UFSHostDevice.hh"
73
74namespace gem5
75{
76
81 uint32_t lun_id, const Callback &transfer_cb,
82 const Callback &read_cb):
83 SimObject(p),
84 flashDisk(p.image[lun_id]),
85 flashDevice(p.internalflash[lun_id]),
86 blkSize(p.img_blk_size),
87 lunAvail(p.image.size()),
88 diskSize(flashDisk->size()),
89 capacityLower((diskSize - 1) & 0xffffffff),
91 lunID(lun_id),
92 transferCompleted(false),
93 readCompleted(false),
94 totalRead(0),
95 totalWrite(0),
98{
104 signalDone = transfer_cb;
105 memReadCallback = [this]() { readCallback(); };
106 deviceReadCallback = read_cb;
107 memWriteCallback = [this]() { SSDWriteDone(); };
108
113 uint32_t temp_id = ((lun_id | 0x30) << 24) | 0x3A4449;
114 lunInfo.dWord0 = 0x02060000; //data
115 lunInfo.dWord1 = 0x0200001F;
116 lunInfo.vendor0 = 0x484D5241; //ARMH (HMRA)
117 lunInfo.vendor1 = 0x424D4143; //CAMB (BMAC)
118 lunInfo.product0 = 0x356D6567; //gem5 (5meg)
119 lunInfo.product1 = 0x4D534655; //UFSM (MSFU)
120 lunInfo.product2 = 0x4C45444F; //ODEL (LEDO)
121 lunInfo.product3 = temp_id; // ID:"lun_id" ("lun_id":DI)
122 lunInfo.productRevision = 0x01000000; //0x01
123
124 DPRINTF(UFSHostDevice, "Logic unit %d assumes that %d logic units are"
125 " present in the system\n", lunID, lunAvail);
126 DPRINTF(UFSHostDevice,"The disksize of lun: %d should be %d blocks\n",
127 lunID, diskSize);
128 flashDevice->initializeMemory(diskSize, SectorSize);
129}
130
131
137const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage[3] =
138 {0x01400A0A, 0x00000000,
139 0x0000FFFF};
140const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage[3] =
141 {0x03800A01, 0x00000000,
142 0xFFFF0003};
143const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage[5] =
144 {0x00011208, 0x00000000,
145 0x00000000, 0x00000020,
146 0x00000000};
147
149
160
163{
164 struct SCSIReply scsi_out;
165 scsi_out.reset();
166
172 lunID << 16;
175 statusCheck(SCSIGood, scsi_out.senseCode);
176 scsi_out.senseSize = scsi_out.senseCode[0];
177 scsi_out.LUN = lunID;
178 scsi_out.status = SCSIGood;
179
180 DPRINTF(UFSHostDevice, "SCSI command:%2x\n", SCSI_msg[4]);
182
183 switch (SCSI_msg[4] & 0xFF) {
184
185 case SCSIInquiry: {
189 scsi_out.msgSize = 36;
190 scsi_out.message.dataMsg.resize(9);
191
192 for (uint8_t count = 0; count < 9; count++)
193 scsi_out.message.dataMsg[count] =
194 (reinterpret_cast<uint32_t*> (&lunInfo))[count];
195 } break;
196
197 case SCSIRead6: {
201 scsi_out.expectMore = 0x02;
202 scsi_out.msgSize = 0;
203
204 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
205
210 uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
211 uint64_t read_offset = betoh(tmp) & 0x1FFFFF;
212
213 uint32_t read_size = tempptr[4];
214
215
216 scsi_out.msgSize = read_size * blkSize;
217 scsi_out.offset = read_offset * blkSize;
218
219 if ((read_offset + read_size) > diskSize)
220 scsi_out.status = SCSIIllegalRequest;
221
222 DPRINTF(UFSHostDevice, "Read6 offset: 0x%8x, for %d blocks\n",
223 read_offset, read_size);
224
228 statusCheck(scsi_out.status, scsi_out.senseCode);
229 scsi_out.senseSize = scsi_out.senseCode[0];
230 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
232
233 } break;
234
235 case SCSIRead10: {
236 scsi_out.expectMore = 0x02;
237 scsi_out.msgSize = 0;
238
239 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
240
242 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
243 uint64_t read_offset = betoh(tmp);
244
245 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
246 uint32_t read_size = betoh(tmpsize);
247
248 scsi_out.msgSize = read_size * blkSize;
249 scsi_out.offset = read_offset * blkSize;
250
251 if ((read_offset + read_size) > diskSize)
252 scsi_out.status = SCSIIllegalRequest;
253
254 DPRINTF(UFSHostDevice, "Read10 offset: 0x%8x, for %d blocks\n",
255 read_offset, read_size);
256
260 statusCheck(scsi_out.status, scsi_out.senseCode);
261 scsi_out.senseSize = scsi_out.senseCode[0];
262 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
264
265 } break;
266
267 case SCSIRead16: {
268 scsi_out.expectMore = 0x02;
269 scsi_out.msgSize = 0;
270
271 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
272
274 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
275 uint64_t read_offset = betoh(tmp);
276
277 tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
278 read_offset = (read_offset << 32) | betoh(tmp);
279
280 tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
281 uint32_t read_size = betoh(tmp);
282
283 scsi_out.msgSize = read_size * blkSize;
284 scsi_out.offset = read_offset * blkSize;
285
286 if ((read_offset + read_size) > diskSize)
287 scsi_out.status = SCSIIllegalRequest;
288
289 DPRINTF(UFSHostDevice, "Read16 offset: 0x%8x, for %d blocks\n",
290 read_offset, read_size);
291
295 statusCheck(scsi_out.status, scsi_out.senseCode);
296 scsi_out.senseSize = scsi_out.senseCode[0];
297 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
299
300 } break;
301
302 case SCSIReadCapacity10: {
306 scsi_out.msgSize = 8;
307 scsi_out.message.dataMsg.resize(2);
308 scsi_out.message.dataMsg[0] =
309 betoh(capacityLower);//last block
310 scsi_out.message.dataMsg[1] = betoh(blkSize);//blocksize
311
312 } break;
313 case SCSIReadCapacity16: {
314 scsi_out.msgSize = 32;
315 scsi_out.message.dataMsg.resize(8);
316 scsi_out.message.dataMsg[0] =
317 betoh(capacityUpper);//last block
318 scsi_out.message.dataMsg[1] =
319 betoh(capacityLower);//last block
320 scsi_out.message.dataMsg[2] = betoh(blkSize);//blocksize
321 scsi_out.message.dataMsg[3] = 0x00;//
322 scsi_out.message.dataMsg[4] = 0x00;//reserved
323 scsi_out.message.dataMsg[5] = 0x00;//reserved
324 scsi_out.message.dataMsg[6] = 0x00;//reserved
325 scsi_out.message.dataMsg[7] = 0x00;//reserved
326
327 } break;
328
329 case SCSIReportLUNs: {
333 scsi_out.msgSize = (lunAvail * 8) + 8;//list + overhead
334 scsi_out.message.dataMsg.resize(2 * lunAvail + 2);
335 scsi_out.message.dataMsg[0] = (lunAvail * 8) << 24;//LUN listlength
336 scsi_out.message.dataMsg[1] = 0x00;
337
338 for (uint8_t count = 0; count < lunAvail; count++) {
339 //LUN "count"
340 scsi_out.message.dataMsg[2 + 2 * count] = (count & 0x7F) << 8;
341 scsi_out.message.dataMsg[3 + 2 * count] = 0x00;
342 }
343
344 } break;
345
346 case SCSIStartStop: {
347 //Just acknowledge; not deemed relevant ATM
348 scsi_out.msgSize = 0;
349
350 } break;
351
352 case SCSITestUnitReady: {
353 //Just acknowledge; not deemed relevant ATM
354 scsi_out.msgSize = 0;
355
356 } break;
357
358 case SCSIVerify10: {
363 scsi_out.msgSize = 0;
364
365 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
366
368 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
369 uint64_t read_offset = betoh(tmp);
370
371 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
372 uint32_t read_size = betoh(tmpsize);
373
374 if ((read_offset + read_size) > diskSize)
375 scsi_out.status = SCSIIllegalRequest;
376
380 statusCheck(scsi_out.status, scsi_out.senseCode);
381 scsi_out.senseSize = scsi_out.senseCode[0];
382 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
384
385 } break;
386
387 case SCSIWrite6: {
391
392 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
393
398 uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
399 uint64_t write_offset = betoh(tmp) & 0x1FFFFF;
400
401 uint32_t write_size = tempptr[4];
402
403 scsi_out.msgSize = write_size * blkSize;
404 scsi_out.offset = write_offset * blkSize;
405 scsi_out.expectMore = 0x01;
406
407 if ((write_offset + write_size) > diskSize)
408 scsi_out.status = SCSIIllegalRequest;
409
410 DPRINTF(UFSHostDevice, "Write6 offset: 0x%8x, for %d blocks\n",
411 write_offset, write_size);
412
416 statusCheck(scsi_out.status, scsi_out.senseCode);
417 scsi_out.senseSize = scsi_out.senseCode[0];
418 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
420
421 } break;
422
423 case SCSIWrite10: {
424 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
425
427 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
428 uint64_t write_offset = betoh(tmp);
429
430 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
431 uint32_t write_size = betoh(tmpsize);
432
433 scsi_out.msgSize = write_size * blkSize;
434 scsi_out.offset = write_offset * blkSize;
435 scsi_out.expectMore = 0x01;
436
437 if ((write_offset + write_size) > diskSize)
438 scsi_out.status = SCSIIllegalRequest;
439
440 DPRINTF(UFSHostDevice, "Write10 offset: 0x%8x, for %d blocks\n",
441 write_offset, write_size);
442
446 statusCheck(scsi_out.status, scsi_out.senseCode);
447 scsi_out.senseSize = scsi_out.senseCode[0];
448 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
450
451 } break;
452
453 case SCSIWrite16: {
454 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
455
457 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
458 uint64_t write_offset = betoh(tmp);
459
460 tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
461 write_offset = (write_offset << 32) | betoh(tmp);
462
463 tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
464 uint32_t write_size = betoh(tmp);
465
466 scsi_out.msgSize = write_size * blkSize;
467 scsi_out.offset = write_offset * blkSize;
468 scsi_out.expectMore = 0x01;
469
470 if ((write_offset + write_size) > diskSize)
471 scsi_out.status = SCSIIllegalRequest;
472
473 DPRINTF(UFSHostDevice, "Write16 offset: 0x%8x, for %d blocks\n",
474 write_offset, write_size);
475
479 statusCheck(scsi_out.status, scsi_out.senseCode);
480 scsi_out.senseSize = scsi_out.senseCode[0];
481 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
483
484 } break;
485
486 case SCSIFormatUnit: {//not yet verified
487 scsi_out.msgSize = 0;
488 scsi_out.expectMore = 0x01;
489
490 } break;
491
492 case SCSISendDiagnostic: {//not yet verified
493 scsi_out.msgSize = 0;
494
495 } break;
496
498 //do we have cache (we don't have cache at this moment)
499 //TODO: here will synchronization happen when cache is modelled
500 scsi_out.msgSize = 0;
501
502 } break;
503
504 //UFS SCSI additional command set for full functionality
505 case SCSIModeSelect10:
506 //TODO:
507 //scsi_out.expectMore = 0x01;//not supported due to modepage support
508 //code isn't dead, code suggest what is to be done when implemented
509 break;
510
511 case SCSIModeSense6: case SCSIModeSense10: {
516 if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x0A) {//control page
517 scsi_out.message.dataMsg.resize((sizeof(controlPage) >> 2) + 2);
518 scsi_out.message.dataMsg[0] = 0x00000A00;//control page code
519 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
520
521 for (uint8_t count = 0; count < 3; count++)
522 scsi_out.message.dataMsg[2 + count] = controlPage[count];
523
524 scsi_out.msgSize = 20;
525 DPRINTF(UFSHostDevice, "CONTROL page\n");
526
527 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
528 scsi_out.message.dataMsg.resize((sizeof(recoveryPage) >> 2)
529 + 2);
530
531 scsi_out.message.dataMsg[0] = 0x00000100;//recovery page code
532 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
533
534 for (uint8_t count = 0; count < 3; count++)
535 scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
536
537 scsi_out.msgSize = 20;
538 DPRINTF(UFSHostDevice, "RECOVERY page\n");
539
540 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x08) {//caching page
541
542 scsi_out.message.dataMsg.resize((sizeof(cachingPage) >> 2) + 2);
543 scsi_out.message.dataMsg[0] = 0x00001200;//caching page code
544 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
545
546 for (uint8_t count = 0; count < 5; count++)
547 scsi_out.message.dataMsg[2 + count] = cachingPage[count];
548
549 scsi_out.msgSize = 20;
550 DPRINTF(UFSHostDevice, "CACHE page\n");
551
552 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
553
554 scsi_out.message.dataMsg.resize(((sizeof(controlPage) +
555 sizeof(recoveryPage) +
556 sizeof(cachingPage)) >> 2)
557 + 2);
558 scsi_out.message.dataMsg[0] = 0x00003200;//all page code
559 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
560
561 for (uint8_t count = 0; count < 3; count++)
562 scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
563
564 for (uint8_t count = 0; count < 5; count++)
565 scsi_out.message.dataMsg[5 + count] = cachingPage[count];
566
567 for (uint8_t count = 0; count < 3; count++)
568 scsi_out.message.dataMsg[10 + count] = controlPage[count];
569
570 scsi_out.msgSize = 52;
571 DPRINTF(UFSHostDevice, "Return ALL the pages!!!\n");
572
573 } else inform("Wrong mode page requested\n");
574
575 scsi_out.message.dataCount = scsi_out.msgSize << 24;
576 } break;
577
578 case SCSIRequestSense: {
579 scsi_out.msgSize = 0;
580
581 } break;
582
583 case SCSIUnmap:break;//not yet verified
584
585 case SCSIWriteBuffer: {
586 scsi_out.expectMore = 0x01;
587
588 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
589
591 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
592 uint64_t write_offset = betoh(tmp) & 0xFFFFFF;
593
594 tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
595 uint32_t write_size = betoh(tmp) & 0xFFFFFF;
596
597 scsi_out.msgSize = write_size;
598 scsi_out.offset = write_offset;
599
600 } break;
601
602 case SCSIReadBuffer: {
608 scsi_out.expectMore = 0x02;
609
610 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
611
613 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
614 uint64_t read_offset = betoh(tmp) & 0xFFFFFF;
615
616 tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
617 uint32_t read_size = betoh(tmp) & 0xFFFFFF;
618
619 scsi_out.msgSize = read_size;
620 scsi_out.offset = read_offset;
621
622 if ((read_offset + read_size) > capacityLower * blkSize)
623 scsi_out.status = SCSIIllegalRequest;
624
625 DPRINTF(UFSHostDevice, "Read buffer location: 0x%8x\n",
626 read_offset);
627 DPRINTF(UFSHostDevice, "Number of bytes: 0x%8x\n", read_size);
628
629 statusCheck(scsi_out.status, scsi_out.senseCode);
630 scsi_out.senseSize = scsi_out.senseCode[0];
631 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
633
634 } break;
635
636 case SCSIMaintenanceIn: {
643 DPRINTF(UFSHostDevice, "Ignoring Maintenance In command\n");
645 scsi_out.senseSize = scsi_out.senseCode[0];
646 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
648 scsi_out.msgSize = 0;
649 } break;
650
651 default: {
653 scsi_out.senseSize = scsi_out.senseCode[0];
654 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
656 scsi_out.msgSize = 0;
657 inform("Unsupported scsi message type: %2x\n", SCSI_msg[4] & 0xFF);
658 inform("0x%8x\n", SCSI_msg[0]);
659 inform("0x%8x\n", SCSI_msg[1]);
660 inform("0x%8x\n", SCSI_msg[2]);
661 inform("0x%8x\n", SCSI_msg[3]);
662 inform("0x%8x\n", SCSI_msg[4]);
663 } break;
664 }
665
666 return scsi_out;
667}
668
674
675void
677 uint8_t* sensecodelist)
678{
679 for (uint8_t count = 0; count < 19; count++)
680 sensecodelist[count] = 0;
681
682 sensecodelist[0] = 18; //sense length
683 sensecodelist[1] = 0x70; //we send a valid frame
684 sensecodelist[3] = status & 0xF; //mask to be sure + sensecode
685 sensecodelist[8] = 0x1F; //data length
686}
687
691
692void
694 uint32_t size)
695{
697 for (int count = 0; count < (size / SectorSize); count++)
698 flashDisk->read(&(readaddr[SectorSize*count]), (offset /
699 SectorSize) + count);
700}
701
705
706void
708 uint32_t size)
709{
711 for (int count = 0; count < (size / SectorSize); count++)
712 flashDisk->write(&(writeaddr[SectorSize * count]),
713 (offset / SectorSize) + count);
714}
715
719
720UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams &p) :
721 DmaDevice(p),
722 pioAddr(p.pio_addr),
723 pioSize(0x0FFF),
724 pioDelay(p.pio_latency),
725 intNum(p.int_num),
726 gic(p.gic),
727 lunAvail(p.image.size()),
728 UFSSlots(p.ufs_slots - 1),
733 countInt(0),
734 transferTrack(0),
737 stats(this),
738 SCSIResumeEvent([this]{ SCSIStart(); }, name()),
739 UTPEvent([this]{ finalUTP(); }, name())
740{
741 DPRINTF(UFSHostDevice, "The hostcontroller hosts %d Logic units\n",
742 lunAvail);
743 UFSDevice.resize(lunAvail);
744
745 for (int count = 0; count < lunAvail; count++) {
746 UFSDevice[count] = new UFSSCSIDevice(p, count,
747 [this]() { LUNSignal(); },
748 [this]() { readCallback(); });
749 }
750
751 if (UFSSlots > 31)
752 warn("UFSSlots = %d, this will results in %d command slots",
753 UFSSlots, (UFSSlots & 0x1F));
754
755 if ((UFSSlots & 0x1F) == 0)
756 fatal("Number of UFS command slots should be between 1 and 32.");
757
758 setValues();
759}
760
763 : statistics::Group(parent, "UFSDiskHost"),
765 "Most up to date length of the command queue"),
767 "Most up to date length of the read SSD queue"),
769 "Most up to date length of the write SSD queue"),
771 ADD_STAT(totalReadSSD, statistics::units::Byte::get(),
772 "Number of bytes read from SSD"),
774 "Number of bytes written to SSD"),
776 "Number of transactions from disk"),
778 "Number of transactions to disk"),
780 "Number of transactions from device"),
782 "Number of transactions to device"),
785 statistics::units::Byte, statistics::units::Second>::get(),
786 "Average read bandwidth",
789 statistics::units::Byte, statistics::units::Second>::get(),
790 "Average write bandwidth",
793 statistics::units::Count, statistics::units::Tick>::get(),
794 "Average command queue length"),
796 statistics::units::Count, statistics::units::Tick>::get(),
797 "Average read queue length"),
799 statistics::units::Count, statistics::units::Tick>::get(),
800 "Average write queue length"),
802 ADD_STAT(curDoorbell, statistics::units::Count::get(),
803 "Most up to date number of doorbells used",
804 parent->activeDoorbells),
805 ADD_STAT(maxDoorbell, statistics::units::Count::get(),
806 "Maximum number of doorbells utilized"),
808 statistics::units::Count, statistics::units::Tick>::get(),
809 "Average number of Doorbells used"),
812 "Histogram of transaction times"),
813 ADD_STAT(idleTimes, statistics::units::Tick::get(), "Histogram of idle times")
814{
815 using namespace statistics;
816
817 // Register the stats
820 .flags(none);
822 .flags(none);
824 .flags(none);
825
828 .flags(none);
829
831 .flags(none);
832
834 .flags(none);
836 .flags(none);
838 .flags(none);
840 .flags(none);
841
844 .flags(nozero);
845
847 .flags(nozero);
848
850 .flags(nozero);
852 .flags(nozero);
854 .flags(nozero);
855
858 .flags(none);
859
861 .flags(none);
863 .flags(nozero);
864
867 .init(100)
868 .flags(pdf);
869
871 .init(100)
872 .flags(pdf);
873}
874
879{
885 UFSHCIMem.HCCAP = 0x06070000 | (UFSSlots & 0x1F);
886 UFSHCIMem.HCversion = 0x00010000; //version is 1.0
887 UFSHCIMem.HCHCDDID = 0xAA003C3C;// Arbitrary number
888 UFSHCIMem.HCHCPMID = 0x41524D48; //ARMH (not an official MIPI number)
889 UFSHCIMem.TRUTRLDBR = 0x00;
890 UFSHCIMem.TMUTMRLDBR = 0x00;
891 UFSHCIMem.CMDUICCMDR = 0x00;
892 // We can process CMD, TM, TR, device present
893 UFSHCIMem.ORHostControllerStatus = 0x08;
894 UFSHCIMem.TRUTRLBA = 0x00;
895 UFSHCIMem.TRUTRLBAU = 0x00;
896 UFSHCIMem.TMUTMRLBA = 0x00;
897 UFSHCIMem.TMUTMRLBAU = 0x00;
898}
899
903
906{
907 AddrRangeList ranges;
908 ranges.push_back(RangeSize(pioAddr, pioSize));
909 return ranges;
910}
911
916
917Tick
919{
920 uint32_t data = 0;
921
922 switch (pkt->getAddr() & 0xFF)
923 {
924
926 data = UFSHCIMem.HCCAP;
927 break;
928
929 case regUFSVersion:
930 data = UFSHCIMem.HCversion;
931 break;
932
934 data = UFSHCIMem.HCHCDDID;
935 break;
936
938 data = UFSHCIMem.HCHCPMID;
939 break;
940
942 data = UFSHCIMem.ORInterruptStatus;
943 UFSHCIMem.ORInterruptStatus = 0x00;
944 //TODO: Revise and extend
946 break;
947
949 data = UFSHCIMem.ORInterruptEnable;
950 break;
951
953 data = UFSHCIMem.ORHostControllerStatus;
954 break;
955
957 data = UFSHCIMem.ORHostControllerEnable;
958 break;
959
961 data = UFSHCIMem.ORUECPA;
962 break;
963
965 data = UFSHCIMem.ORUECDL;
966 break;
967
969 data = UFSHCIMem.ORUECN;
970 break;
971
973 data = UFSHCIMem.ORUECT;
974 break;
975
977 data = UFSHCIMem.ORUECDME;
978 break;
979
981 data = UFSHCIMem.ORUTRIACR;
982 break;
983
985 data = UFSHCIMem.TRUTRLBA;
986 break;
987
989 data = UFSHCIMem.TRUTRLBAU;
990 break;
991
993 data = UFSHCIMem.TRUTRLDBR;
994 break;
995
997 data = UFSHCIMem.TRUTRLCLR;
998 break;
999
1001 data = UFSHCIMem.TRUTRLRSR;
1002 break;
1003
1005 data = UFSHCIMem.TMUTMRLBA;
1006 break;
1007
1009 data = UFSHCIMem.TMUTMRLBAU;
1010 break;
1011
1013 data = UFSHCIMem.TMUTMRLDBR;
1014 break;
1015
1017 data = UFSHCIMem.TMUTMRLCLR;
1018 break;
1019
1021 data = UFSHCIMem.TMUTMRLRSR;
1022 break;
1023
1024 case regUICCommand:
1025 data = UFSHCIMem.CMDUICCMDR;
1026 break;
1027
1028 case regUICCommandArg1:
1029 data = UFSHCIMem.CMDUCMDARG1;
1030 break;
1031
1032 case regUICCommandArg2:
1033 data = UFSHCIMem.CMDUCMDARG2;
1034 break;
1035
1036 case regUICCommandArg3:
1037 data = UFSHCIMem.CMDUCMDARG3;
1038 break;
1039
1040 default:
1041 data = 0x00;
1042 break;
1043 }
1044
1045 pkt->setLE<uint32_t>(data);
1046 pkt->makeResponse();
1047 return pioDelay;
1048}
1049
1055Tick
1057{
1058 assert(pkt->getSize() <= 4);
1059
1060 const uint32_t data = pkt->getUintX(ByteOrder::little);
1061
1062 switch (pkt->getAddr() & 0xFF)
1063 {
1064 case regControllerCapabilities://you shall not write to this
1065 break;
1066
1067 case regUFSVersion://you shall not write to this
1068 break;
1069
1070 case regControllerDEVID://you shall not write to this
1071 break;
1072
1073 case regControllerPRODID://you shall not write to this
1074 break;
1075
1076 case regInterruptStatus://you shall not write to this
1077 break;
1078
1079 case regInterruptEnable:
1080 UFSHCIMem.ORInterruptEnable = data;
1081 break;
1082
1084 UFSHCIMem.ORHostControllerStatus = data;
1085 break;
1086
1088 UFSHCIMem.ORHostControllerEnable = data;
1089 break;
1090
1092 UFSHCIMem.ORUECPA = data;
1093 break;
1094
1096 UFSHCIMem.ORUECDL = data;
1097 break;
1098
1100 UFSHCIMem.ORUECN = data;
1101 break;
1102
1104 UFSHCIMem.ORUECT = data;
1105 break;
1106
1107 case regUICErrorCodeDME:
1108 UFSHCIMem.ORUECDME = data;
1109 break;
1110
1112 UFSHCIMem.ORUTRIACR = data;
1113 break;
1114
1116 UFSHCIMem.TRUTRLBA = data;
1117 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1118 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
1119 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1120 break;
1121
1123 UFSHCIMem.TRUTRLBAU = data;
1124 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1125 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1126 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1127 break;
1128
1130 if (!(UFSHCIMem.TRUTRLDBR) && data)
1131 stats.idleTimes.sample(curTick() - idlePhaseStart);
1132 UFSHCIMem.TRUTRLDBR |= data;
1134 break;
1135
1137 UFSHCIMem.TRUTRLCLR = data;
1138 break;
1139
1141 UFSHCIMem.TRUTRLRSR = data;
1142 break;
1143
1145 UFSHCIMem.TMUTMRLBA = data;
1146 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1147 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1148 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1149 break;
1150
1152 UFSHCIMem.TMUTMRLBAU = data;
1153 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1154 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1155 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1156 break;
1157
1159 UFSHCIMem.TMUTMRLDBR |= data;
1161 break;
1162
1164 UFSHCIMem.TMUTMRLCLR = data;
1165 break;
1166
1168 UFSHCIMem.TMUTMRLRSR = data;
1169 break;
1170
1171 case regUICCommand:
1172 UFSHCIMem.CMDUICCMDR = data;
1174 break;
1175
1176 case regUICCommandArg1:
1177 UFSHCIMem.CMDUCMDARG1 = data;
1178 break;
1179
1180 case regUICCommandArg2:
1181 UFSHCIMem.CMDUCMDARG2 = data;
1182 break;
1183
1184 case regUICCommandArg3:
1185 UFSHCIMem.CMDUCMDARG3 = data;
1186 break;
1187
1188 default:break;//nothing happens, you try to access a register that
1189 //does not exist
1190
1191 }
1192
1193 pkt->makeResponse();
1194 return pioDelay;
1195}
1196
1201
1202void
1204{
1205 Addr address = 0x00;
1206 int mask = 0x01;
1207 int size;
1208 int count = 0;
1209 struct taskStart task_info;
1210 struct transferStart transferstart_info;
1211 transferstart_info.done = 0;
1212
1218 while (((UFSHCIMem.CMDUICCMDR > 0x00) |
1219 ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
1220 ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
1221
1222 if (UFSHCIMem.CMDUICCMDR > 0x00) {
1228 UFSHCIMem.ORInterruptStatus |= UICCommandCOMPL;
1230 UFSHCIMem.CMDUICCMDR = 0x00;
1231 return; //command, nothing more we can do
1232
1233 } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
1238 size = sizeof(UTPUPIUTaskReq);
1240 count = findLsbSet((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack));
1241 address = UFSHCIMem.TMUTMRLBAU;
1242 //<-64 bit
1243 address = (count * size) + (address << 32) +
1244 UFSHCIMem.TMUTMRLBA;
1246
1247 inform("UFSmodel received a task from the system; this might"
1248 " lead to untested behaviour.\n");
1249
1250 task_info.mask = mask << count;
1251 task_info.address = address;
1252 task_info.size = size;
1253 task_info.done = UFSHCIMem.TMUTMRLDBR;
1254 taskInfo.push_back(task_info);
1255 taskEventQueue.push_back(
1256 EventFunctionWrapper([this]{ taskStart(); }, name()));
1257 writeDevice(&taskEventQueue.back(), false, address, size,
1258 reinterpret_cast<uint8_t*>
1259 (&taskInfo.back().destination), 0, 0);
1260
1261 } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
1267 size = sizeof(UTPTransferReqDesc);
1269 count = findLsbSet((UFSHCIMem.TRUTRLDBR ^ transferTrack));
1270 address = UFSHCIMem.TRUTRLBAU;
1271 //<-64 bit
1272 address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
1273
1274 transferTrack |= mask << count;
1275 DPRINTF(UFSHostDevice, "Doorbell register: 0x%8x select #:"
1276 " 0x%8x completion info: 0x%8x\n", UFSHCIMem.TRUTRLDBR,
1277 count, transferstart_info.done);
1278
1279 transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1280
1282 transactionStart[count] = curTick(); //note the start time
1284 stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
1285 ? activeDoorbells : stats.maxDoorbell.value();
1286 stats.averageDoorbell = stats.maxDoorbell.value();
1287
1293 transferstart_info.mask = mask << count;
1294 transferstart_info.address = address;
1295 transferstart_info.size = size;
1296 transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1297 transferStartInfo.push_back(transferstart_info);
1298
1300 transferStartInfo.back().destination = new struct
1302 DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
1303 transferstart_info.done);
1304 transferEventQueue.push_back(
1305 EventFunctionWrapper([this]{ transferStart(); }, name()));
1306
1307 if (transferEventQueue.size() < 2) {
1308 writeDevice(&transferEventQueue.front(), false,
1309 address, size, reinterpret_cast<uint8_t*>
1310 (transferStartInfo.front().destination),0, 0);
1311 DPRINTF(UFSHostDevice, "Transfer scheduled\n");
1312 }
1313 }
1314 }
1315}
1316
1320
1321void
1323{
1324 DPRINTF(UFSHostDevice, "Task start");
1325 taskHandler(&taskInfo.front().destination, taskInfo.front().mask,
1326 taskInfo.front().address, taskInfo.front().size);
1327 taskInfo.pop_front();
1328 taskEventQueue.pop_front();
1329}
1330
1334
1335void
1337{
1338 DPRINTF(UFSHostDevice, "Enter transfer event\n");
1339 transferHandler(transferStartInfo.front().destination,
1340 transferStartInfo.front().mask,
1341 transferStartInfo.front().address,
1342 transferStartInfo.front().size,
1343 transferStartInfo.front().done);
1344
1345 transferStartInfo.pop_front();
1346 DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
1347 "0x%8x\n", transferEventQueue.size());
1348}
1349
1354
1355void
1357{
1358 if (UFSHCIMem.CMDUICCMDR == 0x16) {
1359 UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
1360 }
1361
1362}
1363
1368
1369void
1371 uint32_t req_pos, Addr finaladdress, uint32_t
1372 finalsize)
1373{
1378 inform("taskHandler\n");
1379 inform("%8x\n", request_in->header.dWord0);
1380 inform("%8x\n", request_in->header.dWord1);
1381 inform("%8x\n", request_in->header.dWord2);
1382
1383 request_in->header.dWord2 &= 0xffffff00;
1384
1385 UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
1386 taskCommandTrack &= ~(req_pos);
1387 UFSHCIMem.ORInterruptStatus |= UTPTaskREQCOMPL;
1388
1389 readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
1390 (request_in), true, NULL);
1391
1392}
1393
1404
1405void
1407 int req_pos, Addr finaladdress, uint32_t
1408 finalsize, uint32_t done)
1409{
1410
1411 Addr cmd_desc_addr = 0x00;
1412
1413
1414 //acknowledge handling of the message
1415 DPRINTF(UFSHostDevice, "SCSI message detected\n");
1416 request_in->header.dWord2 &= 0xffffff00;
1417 SCSIInfo.RequestIn = request_in;
1418 SCSIInfo.reqPos = req_pos;
1419 SCSIInfo.finalAddress = finaladdress;
1420 SCSIInfo.finalSize = finalsize;
1421 SCSIInfo.destination.resize(request_in->PRDTableOffset * 4
1422 + request_in->PRDTableLength * sizeof(UFSHCDSGEntry));
1423 SCSIInfo.done = done;
1424
1425 assert(!SCSIResumeEvent.scheduled());
1429 cmd_desc_addr = request_in->commandDescBaseAddrHi;
1430 cmd_desc_addr = (cmd_desc_addr << 32) |
1431 (request_in->commandDescBaseAddrLo & 0xffffffff);
1432
1433 writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
1434 SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
1435
1436 DPRINTF(UFSHostDevice, "SCSI scheduled\n");
1437
1438 transferEventQueue.pop_front();
1439}
1440
1447
1448void
1450{
1451 DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
1452 uint32_t LUN = SCSIInfo.destination[2];
1453 UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
1454
1455 DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
1456 UFSDevice[LUN]->SCSIInfoQueue.size());
1457
1459 if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
1460 SCSIResume(LUN);
1461
1462 else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
1463 panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
1464 SCSIInfoQueue.size());
1465
1470 if (!transferEventQueue.empty()) {
1471
1476 writeDevice(&transferEventQueue.front(), false,
1477 transferStartInfo.front().address,
1478 transferStartInfo.front().size, reinterpret_cast<uint8_t*>
1479 (transferStartInfo.front().destination), 0, 0);
1480
1481 DPRINTF(UFSHostDevice, "Transfer scheduled");
1482 }
1483}
1484
1492
1493void
1495{
1496 DPRINTF(UFSHostDevice, "SCSIresume\n");
1497 if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1498 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1499 UFSHCIMem.TRUTRLDBR);
1500
1502 struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
1503 SCSIInfoQueue.front().RequestIn;
1504
1505 uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
1506
1507 Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
1508 finalAddress;
1509
1510 uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
1511
1512 uint32_t* transfercommand = reinterpret_cast<uint32_t*>
1513 (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
1514
1515 DPRINTF(UFSHostDevice, "Task tag: 0x%8x\n", transfercommand[0]>>24);
1517 request_out_datain = UFSDevice[(transfercommand[0] & 0xFF0000) >> 16]->
1518 SCSICMDHandle(transfercommand);
1519
1520 DPRINTF(UFSHostDevice, "LUN: %d\n", request_out_datain.LUN);
1521
1526 request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
1527 ? 0x36 : 0x21;
1528 UFSDevice[lun_id]->transferInfo.requestOut.header.dWord0 =
1529 request_in->header.dWord0 | (request_out_datain.LUN << 8)
1530 | (transfercommand[0] & 0xFF000000);
1532 UFSDevice[lun_id]->transferInfo.requestOut.header.dWord1 = 0x00000000 |
1533 (request_out_datain.status << 24);
1535 UFSDevice[lun_id]->transferInfo.requestOut.header.dWord2 = 0x00000000 |
1536 ((request_out_datain.senseSize + 2) << 24) | 0x05;
1538 UFSDevice[lun_id]->transferInfo.requestOut.senseDataLen =
1539 request_out_datain.senseSize;
1540
1541 //data
1542 for (uint8_t count = 0; count<request_out_datain.senseSize; count++) {
1543 UFSDevice[lun_id]->transferInfo.requestOut.senseData[count] =
1544 request_out_datain.senseCode[count + 1];
1545 }
1546
1547 /*
1548 * At position defined by "request_in->PRDTableOffset" (counting 32 bit
1549 * words) in array "transfercommand" we have a scatter gather list, which
1550 * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
1551 */
1552 struct UFSHCDSGEntry* sglist = reinterpret_cast<UFSHCDSGEntry*>
1553 (&(transfercommand[(request_in->PRDTableOffset)]));
1554
1555 uint32_t length = request_in->PRDTableLength;
1556 DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
1557
1558 Addr response_addr = request_in->commandDescBaseAddrHi;
1559 response_addr = (response_addr << 32) |
1560 ((request_in->commandDescBaseAddrLo +
1561 (request_in->responseUPIULength << 2)) & 0xffffffff);
1562
1564 UFSDevice[lun_id]->transferInfo.responseStartAddr = response_addr;
1565 UFSDevice[lun_id]->transferInfo.reqPos = req_pos;
1566 UFSDevice[lun_id]->transferInfo.size = finalsize;
1567 UFSDevice[lun_id]->transferInfo.address = finaladdress;
1568 UFSDevice[lun_id]->transferInfo.destination = reinterpret_cast<uint8_t*>
1569 (UFSDevice[lun_id]->SCSIInfoQueue.front().RequestIn);
1570 UFSDevice[lun_id]->transferInfo.finished = true;
1571 UFSDevice[lun_id]->transferInfo.lunID = request_out_datain.LUN;
1572
1578 if (request_out_datain.expectMore == 0x01) {
1581 length, sglist);
1582
1583 } else if (request_out_datain.expectMore == 0x02) {
1586 request_out_datain.offset, length, sglist);
1587
1588 } else {
1590 uint32_t count = 0;
1591 uint32_t size_accum = 0;
1592 DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1593 request_out_datain.msgSize);
1594
1596 while ((length > count) && size_accum
1597 < (request_out_datain.msgSize - 1) &&
1598 (request_out_datain.msgSize != 0x00)) {
1599 Addr SCSI_start = sglist[count].upperAddr;
1600 SCSI_start = (SCSI_start << 32) |
1601 (sglist[count].baseAddr & 0xFFFFFFFF);
1602 DPRINTF(UFSHostDevice, "Data DMA start: 0x%8x\n", SCSI_start);
1603 DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1604 (sglist[count].size + 1));
1612 uint32_t size_to_send = sglist[count].size + 1;
1613
1614 if (request_out_datain.msgSize < (size_to_send + size_accum))
1615 size_to_send = request_out_datain.msgSize - size_accum;
1616
1617 readDevice(false, SCSI_start, size_to_send,
1618 reinterpret_cast<uint8_t*>
1619 (&(request_out_datain.message.dataMsg[size_accum])),
1620 false, NULL);
1621
1622 size_accum += size_to_send;
1623 DPRINTF(UFSHostDevice, "Total remaining: 0x%8x,accumulated so far"
1624 " : 0x%8x\n", (request_out_datain.msgSize - size_accum),
1625 size_accum);
1626
1627 ++count;
1628 DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
1629 }
1630
1632 transferDone(response_addr, req_pos, UFSDevice[lun_id]->
1633 transferInfo.requestOut, finalsize, finaladdress,
1634 reinterpret_cast<uint8_t*>(request_in), true, lun_id);
1635 }
1636
1637 DPRINTF(UFSHostDevice, "SCSI resume done\n");
1638}
1639
1645void
1647{
1648 uint8_t this_lun = 0;
1649
1650 //while we haven't found the right lun, keep searching
1651 while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
1652 ++this_lun;
1653
1654 if (this_lun < lunAvail) {
1655 //Clear signal.
1656 UFSDevice[this_lun]->clearSignal();
1657 //found it; call transferDone
1658 transferDone(UFSDevice[this_lun]->transferInfo.responseStartAddr,
1659 UFSDevice[this_lun]->transferInfo.reqPos,
1660 UFSDevice[this_lun]->transferInfo.requestOut,
1661 UFSDevice[this_lun]->transferInfo.size,
1662 UFSDevice[this_lun]->transferInfo.address,
1663 UFSDevice[this_lun]->transferInfo.destination,
1664 UFSDevice[this_lun]->transferInfo.finished,
1665 UFSDevice[this_lun]->transferInfo.lunID);
1666 }
1667
1668 else
1669 panic("no LUN finished in tick %d\n", curTick());
1670}
1671
1676
1677void
1678UFSHostDevice::transferDone(Addr responseStartAddr, uint32_t req_pos,
1679 struct UTPUPIURSP request_out, uint32_t size,
1680 Addr address, uint8_t* destination,
1681 bool finished, uint32_t lun_id)
1682{
1684 if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1685 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1686 UFSHCIMem.TRUTRLDBR);
1687
1688 DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1689 responseStartAddr, sizeof(request_out));
1690
1691 struct transferStart lastinfo;
1692 lastinfo.mask = req_pos;
1693 lastinfo.done = finished;
1694 lastinfo.address = address;
1695 lastinfo.size = size;
1696 lastinfo.destination = reinterpret_cast<UTPTransferReqDesc*>
1697 (destination);
1698 lastinfo.lun_id = lun_id;
1699
1700 transferEnd.push_back(lastinfo);
1701
1702 DPRINTF(UFSHostDevice, "Transfer done start\n");
1703
1704 readDevice(false, responseStartAddr, sizeof(request_out),
1705 reinterpret_cast<uint8_t*>
1706 (&(UFSDevice[lun_id]->transferInfo.requestOut)),
1707 true, &UTPEvent);
1708}
1709
1715
1716void
1718{
1719 uint32_t lun_id = transferEnd.front().lun_id;
1720
1721 UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
1722 DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
1723 UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
1724
1726 if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
1727 uint8_t count = 0;
1728 while (!(transferEnd.front().mask & (0x1 << count)))
1729 ++count;
1730 stats.transactionLatency.sample(curTick() -
1732 }
1733
1735 readDevice(true, transferEnd.front().address,
1736 transferEnd.front().size, reinterpret_cast<uint8_t*>
1737 (transferEnd.front().destination), true, NULL);
1738
1740 transferTrack &= ~(transferEnd.front().mask);
1743 garbage.push_back(transferEnd.front().destination);
1744 transferEnd.pop_front();
1745 DPRINTF(UFSHostDevice, "UTP handled\n");
1746
1748 stats.averageDoorbell = stats.maxDoorbell.value();
1749
1750 DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
1751 " garbage: %d, TransferEvent: %d\n", activeDoorbells,
1753
1755 if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
1756 SCSIResume(lun_id);
1757}
1758
1762void
1764{
1765 DPRINTF(UFSHostDevice, "Read done start\n");
1767
1769 if (garbage.size() > 0) {
1770 delete garbage.front();
1771 garbage.pop_front();
1772 }
1773
1775 if (!(UFSHCIMem.ORInterruptStatus & 0x01)) {
1776 UFSHCIMem.ORInterruptStatus |= UTPTransferREQCOMPL;
1778 }
1779
1780
1781 if (!readDoneEvent.empty()) {
1782 readDoneEvent.pop_front();
1783 }
1784}
1785
1789
1790void
1792{
1794 countInt++;
1795
1797 UFSHCIMem.TRUTRLDBR &= transferTrack;
1798 pendingDoorbells = 0;
1799 DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
1800
1801 checkDrain();
1802
1804 gic->sendInt(intNum);
1805 DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
1806 countInt);
1807}
1808
1812
1813void
1815{
1816 gic->clearInt(intNum);
1817 DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
1818
1819 checkDrain();
1820
1821 if (!(UFSHCIMem.TRUTRLDBR)) {
1823 }
1825}
1826
1843
1844
1850
1851void
1852UFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
1853 start, int size, uint8_t* destination, uint64_t
1854 SCSIDiskOffset, uint32_t lun_id)
1855{
1856 DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
1857 start, size);
1858
1860 if (toDisk) {
1862
1863 while (!writeDoneEvent.empty() && (writeDoneEvent.front().when()
1864 < curTick()))
1865 writeDoneEvent.pop_front();
1866
1867 writeDoneEvent.push_back(
1868 EventFunctionWrapper([this]{ writeDone(); },
1869 name()));
1870 assert(!writeDoneEvent.back().scheduled());
1871
1873 struct transferInfo new_transfer;
1874 new_transfer.offset = SCSIDiskOffset;
1875 new_transfer.size = size;
1876 new_transfer.lunID = lun_id;
1877 new_transfer.filePointer = 0;
1878 SSDWriteinfo.push_back(new_transfer);
1879
1881 SSDWriteinfo.back().buffer.resize(size);
1882
1884 dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1885 &writeDoneEvent.back(),
1886 &SSDWriteinfo.back().buffer[0], 0);
1887 //yes, a readreq at a write device function is correct.
1888 DPRINTF(UFSHostDevice, "Write to disk scheduled\n");
1889
1890 } else {
1891 assert(!additional_action->scheduled());
1892 dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1893 additional_action, destination, 0);
1894 DPRINTF(UFSHostDevice, "Write scheduled\n");
1895 }
1896}
1897
1902
1903void
1904UFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
1905 sg_table_length, struct UFSHCDSGEntry*
1906 sglist)
1907{
1908 struct writeToDiskBurst next_packet;
1909
1910 next_packet.SCSIDiskOffset = offset;
1911
1912 UFSDevice[LUN]->setTotalWrite(sg_table_length);
1913
1918 for (uint32_t count = 0; count < sg_table_length; count++) {
1919 next_packet.start = sglist[count].upperAddr;
1920 next_packet.start = (next_packet.start << 32) |
1921 (sglist[count].baseAddr & 0xFFFFFFFF);
1922 next_packet.LUN = LUN;
1923 DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n",
1924 next_packet.start);
1925 DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
1926 (sglist[count].size + 1));
1927 assert(sglist[count].size > 0);
1928
1929 if (count != 0)
1930 next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
1931 (sglist[count - 1].size + 1);
1932
1933 next_packet.size = sglist[count].size + 1;
1934
1936 if (dmaWriteInfo.empty())
1937 writeDevice(NULL, true, next_packet.start, next_packet.size,
1938 NULL, next_packet.SCSIDiskOffset, next_packet.LUN);
1939 else
1940 DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
1941 dmaWriteInfo.size());
1942
1943 dmaWriteInfo.push_back(next_packet);
1944 DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
1945 next_packet.SCSIDiskOffset);
1946
1947 DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
1948
1950 stats.totalWrittenSSD += (sglist[count].size + 1);
1951 }
1952
1954 ++stats.totalWriteUFSTransactions;
1955}
1956
1961
1962void
1964{
1966 assert(dmaWriteInfo.size() > 0);
1967 dmaWriteInfo.pop_front();
1968 assert(SSDWriteinfo.size() > 0);
1969 uint32_t lun = SSDWriteinfo.front().lunID;
1970
1972 DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n",
1973 UFSDevice[lun]->SSDWriteDoneInfo.size());
1975 UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
1976 SSDWriteinfo.front().offset,
1977 SSDWriteinfo.front().size);
1978
1984 UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
1985 SSDWriteinfo.pop_front();
1986
1989 UFSDevice[lun]->SSDWriteStart();
1990
1992 stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1993 stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1994 ++stats.totalWriteDiskTransactions;
1995
1997 if (!dmaWriteInfo.empty())
1998 writeDevice(NULL, true, dmaWriteInfo.front().start,
1999 dmaWriteInfo.front().size, NULL,
2000 dmaWriteInfo.front().SCSIDiskOffset,
2001 dmaWriteInfo.front().LUN);
2002 DPRINTF(UFSHostDevice, "Write done end\n");
2003}
2004
2008void
2010{
2011 assert(SSDWriteDoneInfo.size() > 0);
2012 flashDevice->writeMemory(
2013 SSDWriteDoneInfo.front().offset,
2014 SSDWriteDoneInfo.front().size, memWriteCallback);
2015
2016 SSDWriteDoneInfo.pop_front();
2017
2018 DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
2019 SSDWriteDoneInfo.size());
2020}
2021
2022
2026
2027void
2029{
2030 DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
2032
2033 //we have done one extra transfer
2035
2037 assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
2038
2041 DPRINTF(UFSHostDevice, "Write transactions finished\n");
2042 totalWrite = 0;
2044
2045 //Callback UFS Host
2046 setSignal();
2047 signalDone();
2048 }
2049
2050}
2051
2056
2057void
2058UFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
2059 uint8_t* destination, bool no_cache, Event*
2060 additional_action)
2061{
2062 DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2063 start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
2064
2066 if (lastTransfer) {
2068 readDoneEvent.push_back(
2069 EventFunctionWrapper([this]{ readDone(); },
2070 name()));
2071 assert(!readDoneEvent.back().scheduled());
2072 dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2073 &readDoneEvent.back(), destination, 0);
2074 //yes, a writereq at a read device function is correct.
2075
2076 } else {
2077 if (additional_action != NULL)
2078 assert(!additional_action->scheduled());
2079
2080 dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2081 additional_action, destination, 0);
2082
2083 }
2084
2085}
2086
2091
2092void
2093UFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
2094 offset, uint32_t sg_table_length,
2095 struct UFSHCDSGEntry* sglist)
2096{
2097 uint32_t size_accum = 0;
2098
2099 DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
2100
2105 for (uint32_t count = 0; count < sg_table_length; count++) {
2106 struct transferInfo new_transfer;
2107 new_transfer.offset = sglist[count].upperAddr;
2108 new_transfer.offset = (new_transfer.offset << 32) |
2109 (sglist[count].baseAddr & 0xFFFFFFFF);
2110 new_transfer.filePointer = offset + size_accum;
2111 new_transfer.size = (sglist[count].size + 1);
2112 new_transfer.lunID = LUN;
2113
2114 DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
2115 new_transfer.offset, new_transfer.size);
2116
2117 UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
2118 UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
2119 + 1);
2120
2126 UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
2127 SSDReadInfo.back().buffer[0],
2128 offset + size_accum,
2129 sglist[count].size + 1);
2130
2131 size_accum += (sglist[count].size + 1);
2132
2133 DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2134 " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
2135
2137 stats.totalReadSSD += (sglist[count].size + 1);
2138 stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2139 stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2140 }
2141
2142 UFSDevice[LUN]->SSDReadStart(sg_table_length);
2143
2145 ++stats.totalReadUFSTransactions;
2146
2147}
2148
2149
2150
2156
2157void
2159{
2160 totalRead = total_read;
2161 for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
2162 number_handled++) {
2167 flashDevice->readMemory(SSDReadInfo.front().filePointer,
2168 SSDReadInfo.front().size, memReadCallback);
2169 }
2170
2171}
2172
2173
2177
2178void
2180{
2181 DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
2182 " %d so far\n", lunID, totalRead, amountOfReadTransfers);
2183
2185 totalRead = 0;
2187
2189 setSignal();
2190 signalDone();
2191 }
2192
2193}
2194
2199void
2201{
2203
2207 setReadSignal();
2209
2210 //Are we done yet?
2211 SSDReadDone();
2212}
2213
2218
2219void
2221{
2222 DPRINTF(UFSHostDevice, "Read Callback\n");
2223 uint8_t this_lun = 0;
2224
2225 //while we haven't found the right lun, keep searching
2226 while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
2227 ++this_lun;
2228
2229 DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
2230 this_lun, SSDReadPending.size());
2231
2232 if (this_lun < lunAvail) {
2233 //Clear signal.
2234 UFSDevice[this_lun]->clearReadSignal();
2235 SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front());
2236 UFSDevice[this_lun]->SSDReadInfo.pop_front();
2237 readGarbageEventQueue.push_back(
2238 EventFunctionWrapper([this]{ readGarbage(); }, name()));
2239
2240 //make sure the queue is popped a the end of the dma transaction
2241 readDevice(false, SSDReadPending.front().offset,
2242 SSDReadPending.front().size,
2243 &SSDReadPending.front().buffer[0], false,
2244 &readGarbageEventQueue.back());
2245
2247 ++stats.totalReadDiskTransactions;
2248 }
2249 else
2250 panic("no read finished in tick %d\n", curTick());
2251}
2252
2257void
2259{
2260 DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
2261 SSDReadPending.pop_front();
2262 readGarbageEventQueue.pop_front();
2263}
2264
2268
2269void
2271{
2273
2274 const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
2275 SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2276
2277 uint32_t lun_avail = lunAvail;
2278 SERIALIZE_SCALAR(lun_avail);
2279}
2280
2281
2285
2286void
2288{
2290 uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
2291 UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2292
2293 uint32_t lun_avail;
2294 UNSERIALIZE_SCALAR(lun_avail);
2295 assert(lunAvail == lun_avail);
2296}
2297
2298
2302
2305{
2306 if (UFSHCIMem.TRUTRLDBR) {
2307 DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
2308 return DrainState::Draining;
2309 } else {
2310 DPRINTF(UFSHostDevice, "UFSDevice drained\n");
2311 return DrainState::Drained;
2312 }
2313}
2314
2318
2319void
2321{
2323 return;
2324
2325 if (UFSHCIMem.TRUTRLDBR) {
2326 DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
2327 " doorbells\n", activeDoorbells);
2328 } else {
2329 DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
2331 }
2332}
2333
2334} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
const char data[]
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
DmaDevice(const Params &p)
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition packet.hh:1062
unsigned getSize() const
Definition packet.hh:817
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
Definition packet.cc:352
static const unsigned int cachingPage[5]
void SSDWriteStart()
SSD write start.
void SSDReadDone()
SSD Read done; Determines if the final callback of the transaction should be made at the end of a rea...
static const unsigned int controlPage[3]
These pages are SCSI specific.
std::function< void()> Callback
void setSignal()
set signal to indicate that the transaction has been completed.
UFSSCSIDevice(const UFSHostDeviceParams &p, uint32_t lun_id, const Callback &transfer_cb, const Callback &read_cb)
Constructor and destructor.
Definition ufs_device.cc:80
bool transferCompleted
Signals to Host layer 1: signal for transaction completion 2: signal for read action completion.
void writeFlash(uint8_t *writeaddr, uint64_t offset, uint32_t size)
Write flash.
static const unsigned int UPIUHeaderDataIndWord0
std::deque< struct transferInfo > SSDWriteDoneInfo
SSDWriteDoneInfo: Structure from dma to disk, that contains data, and helper info to get it to the ri...
void readFlash(uint8_t *readaddr, uint64_t offset, uint32_t size)
Disk access functions.
void statusCheck(uint8_t status, uint8_t *sensecodelist)
Status of SCSI.
const uint32_t blkSize
Logic unit dimensions.
void setReadSignal()
set signal to indicate that the read action has been completed
Callback signalDone
Callbacks between Host and Device.
std::deque< struct transferInfo > SSDReadInfo
SSDReadInfo: Structure from disk to dma, that contains data, and helper info to get it to the right p...
Callback memReadCallback
Callbacks between Device and Memory.
static const unsigned int recoveryPage[3]
DiskImage * flashDisk
The objects this model links to.
struct SCSIReply SCSICMDHandle(uint32_t *SCSI_msg)
SCSI command handle function; determines what the command is and returns a reply structure that allow...
struct LUNInfo lunInfo
Logic unit info; needed for SCSI Info messages and LU identification.
static const unsigned int UPIUHeaderDataIndWord2
void readCallback()
Functions to indicate that the action to the SSD has completed.
static const unsigned int UPIUHeaderDataIndWord1
uint32_t totalRead
Total amount transactions that need to be made.
void SSDReadStart(uint32_t total_read)
Start the transactions to (and from) the disk The host will queue all the transactions.
uint32_t amountOfWriteTransfers
transaction progress tracking
void SSDWriteDone()
SSD Write Done; This is the callback function for the memory model.
int readPendingNum
Track number of DMA transactions in progress.
void taskHandler(struct UTPUPIUTaskReq *request_in, uint32_t req_pos, Addr finaladdress, uint32_t finalsize)
Task handler function.
std::deque< EventFunctionWrapper > taskEventQueue
Multiple tasks transfers can be scheduled at once for the device, the only thing we know for sure abo...
void generateInterrupt()
set interrupt and sort out the doorbell register.
void writeDone()
Write done After a DMA write with data intended for the disk, this function is called.
std::deque< struct taskStart > taskInfo
When a task/transfer is started it needs information about the task/transfer it is about to perform.
std::deque< struct transferInfo > SSDWriteinfo
Information from DMA transaction to disk.
static const unsigned int UICCommandReady
std::deque< EventFunctionWrapper > transferEventQueue
EventFunctionWrapper SCSIResumeEvent
The events that control the functionality.
void serialize(CheckpointOut &cp) const override
Serialize; needed to make checkpoints.
void transferHandler(struct UTPTransferReqDesc *request_in, int req_pos, Addr finaladdress, uint32_t finalsize, uint32_t done)
Transfer handler function.
Tick transactionStart[32]
Helper for latency stats These variables keep track of the latency for every doorbell.
const Addr pioAddr
Host controller information.
void commandHandler()
Command handler function.
HCIMem UFSHCIMem
Host controller memory.
struct SCSIReply request_out_datain
SCSI reply structure, used for direct answering.
static const unsigned int UTPTaskREQCOMPL
void clearInterrupt()
Interrupt control functions.
static const unsigned int UTPTransferREQCOMPL
Bits of interest within UFS data packages.
static const unsigned int UICCommandCOMPL
void writeDevice(Event *additional_action, bool toDisk, Addr start, int size, uint8_t *destination, uint64_t SCSIDiskOffset, uint32_t lun_id)
DMA transfer functions These allow the host to push/pull the data to the memory The provided event in...
void finalUTP()
final UTP, sends the last acknowledge data structure to the system; prepares the clean up functions.
std::deque< struct writeToDiskBurst > dmaWriteInfo
Information to get a DMA transaction.
uint32_t transferTrack
Track the transfer This is allows the driver to "group" certain transfers together by using a tag in ...
DrainState drain() override
Drain; needed to enable checkpoints.
void setValues()
Initialization function.
void requestHandler()
Handler functions.
void unserialize(CheckpointIn &cp) override
Unserialize; needed to restore from checkpoints.
void manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t sg_table_length, struct UFSHCDSGEntry *sglist)
Disk transfer management functions these set up the queues, and initiated them, leading to the data t...
struct SCSIResumeInfo SCSIInfo
SCSI resume info information structure for SCSI resume.
Tick read(PacketPtr pkt) override
register access functions
struct UFSHostDeviceStats stats
RequestHandler stats.
void readGarbage()
Read garbage A read from disk data structure can vary in size and is therefor allocated on creation.
std::deque< struct transferStart > transferEnd
To finish the transaction one needs information about the original message.
std::deque< EventFunctionWrapper > readDoneEvent
Transfer flow events Basically these events form two queues, one from memory to UFS device (DMA) and ...
uint32_t countInt
interrupt verification This keeps track of the number of interrupts generated.
std::deque< struct UTPTransferReqDesc * > garbage
garbage queue, ensure clearing of the allocated memory
uint8_t activeDoorbells
Statistics helper variables Active doorbells indicates how many doorbells are in teh process of being...
void manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t offset, uint32_t sg_table_length, struct UFSHCDSGEntry *sglist)
Manage read transfer.
std::vector< UFSSCSIDevice * > UFSDevice
logic units connected to the UFS Host device Note again that the "device" as such is represented by o...
std::deque< struct transferInfo > SSDReadPending
Information from the Disk, waiting to be pushed to the DMA.
void SCSIResume(uint32_t lun_id)
Starts the scsi handling function in the apropriate Logic unit, prepares the right data transfer sche...
std::deque< EventFunctionWrapper > writeDoneEvent
Tick write(PacketPtr pkt) override
UFSHCD write function.
std::deque< struct transferStart > transferStartInfo
AddrRangeList getAddrRanges() const override
Address range functions.
std::deque< EventFunctionWrapper > readGarbageEventQueue
Event after a read to clean up the UTP data structures.
EventFunctionWrapper UTPEvent
Wait for the moment where we can send the last frame.
void readCallback()
Read callback Call back function for the logic units to indicate the completion of a read action.
UFSHostDevice(const UFSHostDeviceParams &p)
Constructor for the UFS Host device.
void transferStart()
Transfer Start function.
void taskStart()
Task Start function.
void transferDone(Addr responseStartAddr, uint32_t req_pos, struct UTPUPIURSP request_out, uint32_t size, Addr address, uint8_t *destination, bool finished, uint32_t lun_id)
transfer done, the beginning of the final stage of the transfer.
void LUNSignal()
LU callback function to indicate that the action has completed.
void readDone()
Read done Started at the end of a transaction after the last read action.
void readDevice(bool lastTransfer, Addr SCSIStart, uint32_t SCSISize, uint8_t *SCSIDestination, bool no_cache, Event *additional_action)
Dma transaction function: read device.
void checkDrain()
Checkdrain; needed to enable checkpoints.
const uint32_t lunAvail
const uint8_t UFSSlots
void SCSIStart()
Transfer SCSI function.
#define SectorSize
Definition disk_image.hh:44
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
AddrRange RangeSize(Addr start, Addr size)
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
constexpr int findLsbSet(uint64_t val)
Returns the bit position of the LSB that is set in the input That function will either use a builtin ...
Definition bitfield.hh:369
void signalDrainDone() const
Signal that an object is drained.
Definition drain.hh:310
DrainState drainState() const
Return the current drain state of an object.
Definition drain.hh:329
DrainState
Object drain/handover states.
Definition drain.hh:76
@ Draining
Draining buffers pending serialization/handover.
Definition drain.hh:78
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:79
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:232
#define UNSERIALIZE_ARRAY(member, size)
Definition serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition serialize.hh:610
SimObject(const Params &p)
Definition sim_object.cc:58
#define warn(...)
Definition logging.hh:288
#define inform(...)
Definition logging.hh:289
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 5, 0 > status
Bitfield< 0 > p
Units for Stats.
Definition units.hh:113
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition info.hh:61
const FlagsType nozero
Don't print if this is zero.
Definition info.hh:67
const FlagsType none
Nothing extra to print.
Definition info.hh:53
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
T betoh(T value)
Definition byteswap.hh:175
uint64_t Tick
Tick count type.
Definition types.hh:58
Packet * PacketPtr
statistics::Formula & simSeconds
Definition stats.cc:45
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
Host Controller Interface This is a set of registers that allow the driver to control the transaction...
SCSI reply structure.
struct UFSHCDSGEntry - UFSHCI PRD Entry baseAddr: Lower 32bit physical address DW-0 upperAddr: Upper ...
statistics::Average averageSCSIQueue
Average Queue lengths.
statistics::Formula averageReadSSDBW
Average bandwidth for reads and writes.
statistics::Scalar totalWriteDiskTransactions
UFSHostDeviceStats(UFSHostDevice *parent)
Amount of data read/written.
statistics::Histogram transactionLatency
Histogram of latencies.
statistics::Scalar totalReadSSD
Amount of data read/written.
statistics::Formula curDoorbell
Number of doorbells rung.
statistics::Scalar currentSCSIQueue
Queue lengths.
std::vector< uint32_t > dataMsg
struct UTPUPIUHeader header
struct UTPTransferReqDesc - UTRD structure header: UTRD header DW-0 to DW-3 commandDescBaseAddrLo: UC...
struct gem5::UFSHostDevice::UTPTransferReqDesc::RequestDescHeader header
struct UTPUPIURSP - Response UPIU structure header: UPIU header DW-0 to DW-2 residualTransferCount: R...
struct UTPUPIUTaskReq - Task request UPIU structure header - UPIU header structure DW0 to DW-2 inputP...
Task start information.
Different events, and scenarios require different types of information.
Transfer start information.
struct UTPTransferReqDesc * destination
Disk transfer burst information.
const std::string & name()
Definition trace.cc:48
This is a base class for UFS devices The UFS interface consists out of one host controller which conn...

Generated on Mon Oct 27 2025 04:13:01 for gem5 by doxygen 1.14.0