flash_device.cc revision 10910:32f3d1c454ec
17090SN/A/* 27090SN/A * Copyright (c) 2013-2015 ARM Limited 37090SN/A * All rights reserved 47090SN/A * 57090SN/A * The license below extends only to copyright in the software and shall 67090SN/A * not be construed as granting a license to any other intellectual 77090SN/A * property including but not limited to intellectual property relating 87090SN/A * to a hardware implementation of the functionality of the software 97090SN/A * licensed hereunder. You may use the software subject to the license 107090SN/A * terms below provided that you ensure that this notice is replicated 117090SN/A * unmodified and in its entirety in all distributions of the software, 127090SN/A * modified or unmodified, in source code or in binary form. 134486SN/A * 144486SN/A * Redistribution and use in source and binary forms, with or without 154486SN/A * modification, are permitted provided that the following conditions are 164486SN/A * met: redistributions of source code must retain the above copyright 174486SN/A * notice, this list of conditions and the following disclaimer; 184486SN/A * redistributions in binary form must reproduce the above copyright 194486SN/A * notice, this list of conditions and the following disclaimer in the 204486SN/A * documentation and/or other materials provided with the distribution; 214486SN/A * neither the name of the copyright holders nor the names of its 224486SN/A * contributors may be used to endorse or promote products derived from 234486SN/A * this software without specific prior written permission. 244486SN/A * 254486SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 264486SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 274486SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 284486SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 294486SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 304486SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 314486SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 324486SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 334486SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 344486SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 354486SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 364486SN/A * 374486SN/A * Authors: Rene de Jong 384486SN/A */ 397584SAli.Saidi@arm.com 407584SAli.Saidi@arm.com/** @file 414486SN/A * This simplistic flash model is designed to model managed SLC NAND flash. 423630SN/A * This device will need an interface module (such as NVMe or UFS); Note that 433630SN/A * this model only calculates the delay and does not perform the actual 447587SAli.Saidi@arm.com * transaction. 455478SN/A * 465478SN/A * To access the memory, use either readMemory or writeMemory. This will 477584SAli.Saidi@arm.com * schedule an event at the tick where the action will finish. If a callback 483630SN/A * has been given as argument then that function will be called on completion 497584SAli.Saidi@arm.com * of that event. Note that this does not guarantee that there are no other 507584SAli.Saidi@arm.com * actions pending in the flash device. 517584SAli.Saidi@arm.com * 527584SAli.Saidi@arm.com * IMPORTANT: number of planes should be a power of 2. 533898SN/A */ 547587SAli.Saidi@arm.com 557587SAli.Saidi@arm.com#include "dev/arm/flash_device.hh" 567587SAli.Saidi@arm.com 577587SAli.Saidi@arm.com#include "debug/Drain.hh" 587587SAli.Saidi@arm.com 597584SAli.Saidi@arm.com/** 607584SAli.Saidi@arm.com * Create this device 617584SAli.Saidi@arm.com */ 627584SAli.Saidi@arm.com 637584SAli.Saidi@arm.comFlashDevice* 647584SAli.Saidi@arm.comFlashDeviceParams::create() 657584SAli.Saidi@arm.com{ 667584SAli.Saidi@arm.com return new FlashDevice(this); 677584SAli.Saidi@arm.com} 687584SAli.Saidi@arm.com 697584SAli.Saidi@arm.com 707584SAli.Saidi@arm.com/** 717584SAli.Saidi@arm.com * Flash Device constructor and destructor 727584SAli.Saidi@arm.com */ 737584SAli.Saidi@arm.com 747584SAli.Saidi@arm.comFlashDevice::FlashDevice(const FlashDeviceParams* p): 757584SAli.Saidi@arm.com AbstractNVM(p), 767584SAli.Saidi@arm.com diskSize(0), 777584SAli.Saidi@arm.com blockSize(p->blk_size), 787584SAli.Saidi@arm.com pageSize(p->page_size), 797584SAli.Saidi@arm.com GCActivePercentage(p->GC_active), 807584SAli.Saidi@arm.com readLatency(p->read_lat), 817584SAli.Saidi@arm.com writeLatency(p->write_lat), 827584SAli.Saidi@arm.com eraseLatency(p->erase_lat), 837584SAli.Saidi@arm.com dataDistribution(p->data_distribution), 847584SAli.Saidi@arm.com numPlanes(p->num_planes), 857584SAli.Saidi@arm.com pagesPerBlock(0), 867584SAli.Saidi@arm.com pagesPerDisk(0), 877584SAli.Saidi@arm.com blocksPerDisk(0), 887584SAli.Saidi@arm.com planeMask(numPlanes - 1), 897584SAli.Saidi@arm.com drainManager(NULL), 907584SAli.Saidi@arm.com planeEventQueue(numPlanes), 917584SAli.Saidi@arm.com planeEvent(this) 927584SAli.Saidi@arm.com{ 937584SAli.Saidi@arm.com 943630SN/A /* 953630SN/A * Let 'a' be a power of two of n bits, written such that a-n is the msb 967584SAli.Saidi@arm.com * and a-0 is the lsb. Since it is a power of two, only one bit (a-x, 977584SAli.Saidi@arm.com * with 0 <= x <= n) is set. If we subtract one from this number the bits 987584SAli.Saidi@arm.com * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a 997584SAli.Saidi@arm.com * bitwise AND with those two numbers results in an integer with all bits 1007584SAli.Saidi@arm.com * cleared. 1017584SAli.Saidi@arm.com */ 1027584SAli.Saidi@arm.com if(numPlanes & planeMask) 1037584SAli.Saidi@arm.com fatal("Number of planes is not a power of 2 in flash device.\n"); 1047584SAli.Saidi@arm.com} 1057584SAli.Saidi@arm.com 1067584SAli.Saidi@arm.com/** 1077584SAli.Saidi@arm.com * Initiates all the flash functions: initializes the lookup tables, age of 1087584SAli.Saidi@arm.com * the device, etc. This can only be done once the disk image is known. 1097584SAli.Saidi@arm.com * Thats why it can't be done in the constructor. 1107584SAli.Saidi@arm.com */ 1117584SAli.Saidi@arm.comvoid 1127584SAli.Saidi@arm.comFlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size) 1137584SAli.Saidi@arm.com{ 1147584SAli.Saidi@arm.com diskSize = disk_size * sector_size; 1157584SAli.Saidi@arm.com pagesPerBlock = blockSize / pageSize; 1167584SAli.Saidi@arm.com pagesPerDisk = diskSize / pageSize; 1177584SAli.Saidi@arm.com blocksPerDisk = diskSize / blockSize; 1187584SAli.Saidi@arm.com 1197584SAli.Saidi@arm.com /** Sanity information: check flash configuration */ 1207584SAli.Saidi@arm.com DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages " 1217584SAli.Saidi@arm.com "per disk\n", diskSize, pagesPerBlock, pagesPerDisk); 1227584SAli.Saidi@arm.com 1237584SAli.Saidi@arm.com locationTable.resize(pagesPerDisk); 1247584SAli.Saidi@arm.com 1254104SN/A /**Garbage collection related*/ 1264104SN/A blockValidEntries.resize(blocksPerDisk, 0); 1277584SAli.Saidi@arm.com blockEmptyEntries.resize(blocksPerDisk, pagesPerBlock); 1287584SAli.Saidi@arm.com 1294104SN/A /** 1303630SN/A * This is a bitmap. Every bit is a page 1313630SN/A * unknownPages is a vector of 32 bit integers. If every page was an 1323630SN/A * integer, the total size would be pagesPerDisk; since we can map one 1333630SN/A * page per bit we need ceil(pagesPerDisk/32) entries. 32 = 1 << 5 hence 1347584SAli.Saidi@arm.com * it will do to just shift pagesPerDisk five positions and add one. This 1357584SAli.Saidi@arm.com * will allocate one integer to many for this data structure in the worst 1367584SAli.Saidi@arm.com * case. 1377584SAli.Saidi@arm.com */ 1387584SAli.Saidi@arm.com unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF); 1397584SAli.Saidi@arm.com 1407584SAli.Saidi@arm.com for (uint32_t count = 0; count < pagesPerDisk; count++) { 1417584SAli.Saidi@arm.com //setup lookup table + physical aspects 1427584SAli.Saidi@arm.com 1437584SAli.Saidi@arm.com if (dataDistribution == Enums::stripe) { 1447584SAli.Saidi@arm.com locationTable[count].page = count / blocksPerDisk; 1457584SAli.Saidi@arm.com locationTable[count].block = count % blocksPerDisk; 1467584SAli.Saidi@arm.com 1477584SAli.Saidi@arm.com } else { 1487584SAli.Saidi@arm.com locationTable[count].page = count % pagesPerBlock; 1497584SAli.Saidi@arm.com locationTable[count].block = count / pagesPerBlock; 1507584SAli.Saidi@arm.com } 1517584SAli.Saidi@arm.com } 1527584SAli.Saidi@arm.com} 1537584SAli.Saidi@arm.com 1547584SAli.Saidi@arm.comFlashDevice::~FlashDevice() 1557584SAli.Saidi@arm.com{ 1567584SAli.Saidi@arm.com DPRINTF(FlashDevice, "Remove FlashDevice\n"); 1577584SAli.Saidi@arm.com} 1587584SAli.Saidi@arm.com 1597584SAli.Saidi@arm.com/** 1607584SAli.Saidi@arm.com * Handles the accesses to the device. 1617584SAli.Saidi@arm.com * The function determines when certain actions are scheduled and schedules 1627584SAli.Saidi@arm.com * an event that uses the callback function on completion of the action. 1637584SAli.Saidi@arm.com */ 1647584SAli.Saidi@arm.comvoid 1657584SAli.Saidi@arm.comFlashDevice::accessDevice(uint64_t address, uint32_t amount, Callback *event, 1667584SAli.Saidi@arm.com Actions action) 1677584SAli.Saidi@arm.com{ 1687584SAli.Saidi@arm.com DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n" 1697584SAli.Saidi@arm.com , amount, pageSize); 1707584SAli.Saidi@arm.com 1717584SAli.Saidi@arm.com std::vector<Tick> time(numPlanes, 0); 1727584SAli.Saidi@arm.com uint64_t logic_page_addr = address / pageSize; 1737584SAli.Saidi@arm.com uint32_t plane_address = 0; 1747584SAli.Saidi@arm.com 1757584SAli.Saidi@arm.com /** 1767584SAli.Saidi@arm.com * The access will be broken up in a number of page accesses. The number 1777584SAli.Saidi@arm.com * of page accesses depends on the amount that needs to be transfered. 1787584SAli.Saidi@arm.com * The assumption here is that the interface is completely ignorant of 1797584SAli.Saidi@arm.com * the page size and that this model has to figure out all of the 1807584SAli.Saidi@arm.com * transaction characteristics. 1817584SAli.Saidi@arm.com */ 1827584SAli.Saidi@arm.com for (uint32_t count = 0; amount > (count * pageSize); count++) { 1837584SAli.Saidi@arm.com uint32_t index = (locationTable[logic_page_addr].block * 1847584SAli.Saidi@arm.com pagesPerBlock) + (logic_page_addr % pagesPerBlock); 1857584SAli.Saidi@arm.com 1867584SAli.Saidi@arm.com DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d," 1877584SAli.Saidi@arm.com " logic address 0x%8x\n", index, 1887584SAli.Saidi@arm.com locationTable[logic_page_addr].block, pagesPerBlock, 1897584SAli.Saidi@arm.com logic_page_addr); 1907584SAli.Saidi@arm.com DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count, 1917584SAli.Saidi@arm.com (count * pageSize)); 1927584SAli.Saidi@arm.com 1937584SAli.Saidi@arm.com plane_address = locationTable[logic_page_addr].block & planeMask; 1947584SAli.Saidi@arm.com 1957584SAli.Saidi@arm.com if (action == ActionRead) { 1967584SAli.Saidi@arm.com //lookup 1977584SAli.Saidi@arm.com //call accessTimes 1987584SAli.Saidi@arm.com time[plane_address] += accessTimes(locationTable[logic_page_addr] 1997584SAli.Saidi@arm.com .block, ActionRead); 2007584SAli.Saidi@arm.com 2017584SAli.Saidi@arm.com /*stats*/ 2027584SAli.Saidi@arm.com stats.readAccess.sample(logic_page_addr); 2037584SAli.Saidi@arm.com stats.readLatency.sample(time[plane_address]); 2047584SAli.Saidi@arm.com } else { //write 2057584SAli.Saidi@arm.com //lookup 2067584SAli.Saidi@arm.com //call accessTimes if appropriate, page may be unknown, so lets 2077584SAli.Saidi@arm.com //give it the benefit of the doubt 2087584SAli.Saidi@arm.com 2097584SAli.Saidi@arm.com if (getUnknownPages(index)) 2107584SAli.Saidi@arm.com time[plane_address] += accessTimes 2117584SAli.Saidi@arm.com (locationTable[logic_page_addr].block, ActionWrite); 2127584SAli.Saidi@arm.com 2137584SAli.Saidi@arm.com else //A remap is needed 2147584SAli.Saidi@arm.com time[plane_address] += remap(logic_page_addr); 2157584SAli.Saidi@arm.com 2167584SAli.Saidi@arm.com /*stats*/ 2177584SAli.Saidi@arm.com stats.writeAccess.sample(logic_page_addr); 218 stats.writeLatency.sample(time[plane_address]); 219 } 220 221 /** 222 * Check if the page is known and used. unknownPages is a bitmap of 223 * all the pages. It tracks wether we can be sure that the 224 * information of this page is taken into acount in the model (is it 225 * considered in blockValidEntries and blockEmptyEntries?). If it has 226 * been used in the past, then it is known. 227 */ 228 if (getUnknownPages(index)) { 229 clearUnknownPages(index); 230 --blockEmptyEntries[locationTable[logic_page_addr].block]; 231 ++blockValidEntries[locationTable[logic_page_addr].block]; 232 } 233 234 stats.fileSystemAccess.sample(address); 235 ++logic_page_addr; 236 } 237 238 /** 239 * previous part of the function found the times spend in different 240 * planes, now lets find the maximum to know when to callback the disk 241 */ 242 for (uint32_t count = 0; count < numPlanes; count++){ 243 plane_address = (time[plane_address] > time[count]) ? plane_address 244 : count; 245 246 DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count, 247 time[count]); 248 249 if (time[count] != 0) { 250 251 struct CallBackEntry cbe; 252 /** 253 * If there are no events for this plane, then add the current 254 * time to the occupation time; otherwise, plan it after the 255 * last event. If by chance that event is handled in this tick, 256 * then we would still end up with the same result. 257 */ 258 if (planeEventQueue[count].empty()) 259 cbe.time = time[count] + curTick(); 260 else 261 cbe.time = time[count] + 262 planeEventQueue[count].back().time; 263 cbe.function = NULL; 264 planeEventQueue[count].push_back(cbe); 265 266 DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time); 267 268 if (!planeEvent.scheduled()) 269 schedule(planeEvent, planeEventQueue[count].back().time); 270 else if (planeEventQueue[count].back().time < planeEvent.when()) 271 reschedule(planeEvent, 272 planeEventQueue[plane_address].back().time, true); 273 } 274 } 275 276 //worst case two plane finish at the same time, each triggers an event 277 //and this callback will be called once. Maybe before the other plane 278 //could execute its event, but in the same tick. 279 planeEventQueue[plane_address].back().function = event; 280 DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n", 281 plane_address, planeEventQueue[plane_address].size()); 282 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when()); 283} 284 285/** 286 * When a plane completes its action, this event is triggered. When a 287 * callback function was associated with that event, it will be called. 288 */ 289 290void 291FlashDevice::actionComplete() 292{ 293 DPRINTF(FlashDevice, "Plane action completed\n"); 294 uint8_t plane_address = 0; 295 296 uint8_t next_event = 0; 297 298 /**Search for a callback that is supposed to happen in this Tick*/ 299 for (plane_address = 0; plane_address < numPlanes; plane_address++) { 300 if (!planeEventQueue[plane_address].empty()) { 301 /** 302 * Invariant: All queued events are scheduled in the present 303 * or future. 304 */ 305 assert(planeEventQueue[plane_address].front().time >= curTick()); 306 307 if (planeEventQueue[plane_address].front().time == curTick()) { 308 /** 309 * To ensure that the follow-up action is executed correctly, 310 * the callback entry first need to be cleared before it can 311 * be called. 312 */ 313 Callback *temp = planeEventQueue[plane_address].front(). 314 function; 315 planeEventQueue[plane_address].pop_front(); 316 317 /**Found a callback, lets make it happen*/ 318 if (temp != NULL) { 319 DPRINTF(FlashDevice, "Callback, %d\n", plane_address); 320 temp->process(); 321 } 322 } 323 } 324 } 325 326 /** Find when to schedule the planeEvent next */ 327 for (plane_address = 0; plane_address < numPlanes; plane_address++) { 328 if (!planeEventQueue[plane_address].empty()) 329 if (planeEventQueue[next_event].empty() || 330 (planeEventQueue[plane_address].front().time < 331 planeEventQueue[next_event].front().time)) 332 next_event = plane_address; 333 } 334 335 /**Schedule the next plane that will be ready (if any)*/ 336 if (!planeEventQueue[next_event].empty()) { 337 DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address); 338 reschedule(planeEvent, planeEventQueue[next_event].front().time, true); 339 } 340 341 checkDrain(); 342 343 DPRINTF(FlashDevice, "returing from flash event\n"); 344 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when()); 345} 346 347/** 348 * Handles the remapping of the pages. It is a (I hope) sensible statistic 349 * approach. asumption: garbage collection happens when a clean is needed 350 * (may become stochastic function). 351 */ 352Tick 353FlashDevice::remap(uint64_t logic_page_addr) 354{ 355 /** 356 * Are there any empty left in this Block, or do we need to do an erase 357 */ 358 if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) { 359 //just a remap 360 //update tables 361 --blockEmptyEntries[locationTable[logic_page_addr].block]; 362 //access to this table won't be sequential anymore 363 locationTable[logic_page_addr].page = pagesPerBlock + 2; 364 //access new block 365 Tick time = accessTimes(locationTable[logic_page_addr].block, 366 ActionWrite); 367 368 DPRINTF(FlashDevice, "Remap returns %d ticks\n", time); 369 return time; 370 371 } else { 372 //calculate how much time GC would have taken 373 uint32_t block = locationTable[logic_page_addr].block; 374 Tick time = ((GCActivePercentage * 375 (accessTimes(block, ActionCopy) + 376 accessTimes(block, ActionErase))) 377 / 100); 378 379 //use block as the logical start address of the block 380 block = locationTable[logic_page_addr].block * pagesPerBlock; 381 382 //assumption: clean will improve locality 383 for (uint32_t count = 0; count < pageSize; count++) { 384 locationTable[block + count].page = (block + count) % 385 pagesPerBlock; 386 ++count; 387 } 388 389 blockEmptyEntries[locationTable[logic_page_addr].block] = 390 pagesPerBlock; 391 /*stats*/ 392 ++stats.totalGCActivations; 393 394 DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n", 395 time); 396 397 return time; 398 } 399 400} 401 402/** 403 * Calculates the accesstime per operation needed 404 */ 405Tick 406FlashDevice::accessTimes(uint64_t block, Actions action) 407{ 408 Tick time = 0; 409 410 switch(action) { 411 case ActionRead: { 412 /**Just read the page*/ 413 time = readLatency; 414 } break; 415 416 case ActionWrite: { 417 /**Write the page, and read the result*/ 418 time = writeLatency + readLatency; 419 } break; 420 421 case ActionErase: { 422 /**Erase and check wether it was successfull*/ 423 time = eraseLatency + readLatency; 424 } break; 425 426 case ActionCopy: { 427 /**Copy every valid page*/ 428 uint32_t validpages = blockValidEntries[block]; 429 time = validpages * (readLatency + writeLatency); 430 } break; 431 432 default: break; 433 } 434 435 //Used to determine sequential action. 436 DPRINTF(FlashDevice, "Access returns %d ticks\n", time); 437 return time; 438} 439 440/** 441 * clearUnknownPages. defines that a page is known and used 442 * unknownPages is a bitmap of all the pages. It tracks wether we can be sure 443 * that the information of this page is taken into acount in the model (is it 444 * considered in blockValidEntries and blockEmptyEntries?). If it has been 445 * used in the past, then it is known. But it needs to be tracked to make 446 * decisions about write accesses, and indirectly about copy actions. one 447 * unknownPage entry is a 32 bit integer. So if we have a page index, then 448 * that means that we need entry floor(index/32) (index >> 5) and we need to 449 * select the bit which number is equal to the remainder of index/32 450 * (index%32). The bit is cleared to make sure that we see it as considered 451 * in the future. 452 */ 453 454inline 455void 456FlashDevice::clearUnknownPages(uint32_t index) 457{ 458 unknownPages[index >> 5] &= ~(0x01 << (index % 32)); 459} 460 461/** 462 * getUnknownPages. Verify wether a page is known 463 */ 464 465inline 466bool 467FlashDevice::getUnknownPages(uint32_t index) 468{ 469 return unknownPages[index >> 5] & (0x01 << (index % 32)); 470} 471 472void 473FlashDevice::regStats() 474{ 475 using namespace Stats; 476 477 std::string fd_name = name() + ".FlashDevice"; 478 479 // Register the stats 480 /** Amount of GC activations*/ 481 stats.totalGCActivations 482 .name(fd_name + ".totalGCActivations") 483 .desc("Number of Garbage collector activations") 484 .flags(none); 485 486 /** Histogram of address accesses*/ 487 stats.writeAccess 488 .init(2) 489 .name(fd_name + ".writeAccessHist") 490 .desc("Histogram of write addresses") 491 .flags(pdf); 492 stats.readAccess 493 .init(2) 494 .name(fd_name + ".readAccessHist") 495 .desc("Histogram of read addresses") 496 .flags(pdf); 497 stats.fileSystemAccess 498 .init(100) 499 .name(fd_name + ".fileSystemAccessHist") 500 .desc("Histogram of file system accesses") 501 .flags(pdf); 502 503 /** Histogram of access latencies*/ 504 stats.writeLatency 505 .init(100) 506 .name(fd_name + ".writeLatencyHist") 507 .desc("Histogram of write latency") 508 .flags(pdf); 509 stats.readLatency 510 .init(100) 511 .name(fd_name + ".readLatencyHist") 512 .desc("Histogram of read latency") 513 .flags(pdf); 514} 515 516/** 517 * Serialize; needed to create checkpoints 518 */ 519 520void 521FlashDevice::serialize(CheckpointOut &cp) const 522{ 523 SERIALIZE_SCALAR(planeMask); 524 525 int unknown_pages_size = unknownPages.size(); 526 SERIALIZE_SCALAR(unknown_pages_size); 527 for (uint32_t count = 0; count < unknownPages.size(); count++) 528 SERIALIZE_SCALAR(unknownPages[count]); 529 530 int location_table_size = locationTable.size(); 531 SERIALIZE_SCALAR(location_table_size); 532 for (uint32_t count = 0; count < location_table_size; count++) { 533 SERIALIZE_SCALAR(locationTable[count].page); 534 SERIALIZE_SCALAR(locationTable[count].block); 535 } 536 537 int block_valid_entries_size = blockValidEntries.size(); 538 SERIALIZE_SCALAR(block_valid_entries_size); 539 for (uint32_t count = 0; count < blockValidEntries.size(); count++) 540 SERIALIZE_SCALAR(blockValidEntries[count]); 541 542 int block_empty_entries_size = blockEmptyEntries.size(); 543 SERIALIZE_SCALAR(block_empty_entries_size); 544 for (uint32_t count = 0; count < blockEmptyEntries.size(); count++) 545 SERIALIZE_SCALAR(blockEmptyEntries[count]); 546 547}; 548 549/** 550 * Unserialize; needed to restore from checkpoints 551 */ 552 553void 554FlashDevice::unserialize(CheckpointIn &cp) 555{ 556 UNSERIALIZE_SCALAR(planeMask); 557 558 int unknown_pages_size; 559 UNSERIALIZE_SCALAR(unknown_pages_size); 560 unknownPages.resize(unknown_pages_size); 561 for (uint32_t count = 0; count < unknown_pages_size; count++) 562 UNSERIALIZE_SCALAR(unknownPages[count]); 563 564 int location_table_size; 565 UNSERIALIZE_SCALAR(location_table_size); 566 locationTable.resize(location_table_size); 567 for (uint32_t count = 0; count < location_table_size; count++) { 568 UNSERIALIZE_SCALAR(locationTable[count].page); 569 UNSERIALIZE_SCALAR(locationTable[count].block); 570 } 571 572 int block_valid_entries_size; 573 UNSERIALIZE_SCALAR(block_valid_entries_size); 574 blockValidEntries.resize(block_valid_entries_size); 575 for (uint32_t count = 0; count < block_valid_entries_size; count++) 576 UNSERIALIZE_SCALAR(blockValidEntries[count]); 577 578 int block_empty_entries_size; 579 UNSERIALIZE_SCALAR(block_empty_entries_size); 580 blockEmptyEntries.resize(block_empty_entries_size); 581 for (uint32_t count = 0; count < block_empty_entries_size; count++) 582 UNSERIALIZE_SCALAR(blockEmptyEntries[count]); 583 584}; 585 586/** 587 * Drain; needed to enable checkpoints 588 */ 589 590unsigned int 591FlashDevice::drain(DrainManager *dm) 592{ 593 unsigned int count = 0; 594 595 if (planeEvent.scheduled()) { 596 count = 1; 597 drainManager = dm; 598 } else { 599 DPRINTF(Drain, "Flash device in drained state\n"); 600 } 601 602 if (count) { 603 DPRINTF(Drain, "Flash device is draining...\n"); 604 setDrainState(DrainState::Draining); 605 } else { 606 DPRINTF(Drain, "Flash device drained\n"); 607 setDrainState(DrainState::Drained); 608 } 609 return count; 610} 611 612/** 613 * Checkdrain; needed to enable checkpoints 614 */ 615 616void 617FlashDevice::checkDrain() 618{ 619 if (drainManager == NULL) { 620 return; 621 } 622 623 if (planeEvent.when() > curTick()) { 624 DPRINTF(Drain, "Flash device is still draining\n"); 625 } else { 626 DPRINTF(Drain, "Flash device is done draining\n"); 627 drainManager->signalDrainDone(); 628 drainManager = NULL; 629 } 630} 631