flash_device.cc revision 11523
110801Srene.dejong@arm.com/*
210801Srene.dejong@arm.com * Copyright (c) 2013-2015 ARM Limited
310801Srene.dejong@arm.com * All rights reserved
410801Srene.dejong@arm.com *
510801Srene.dejong@arm.com * The license below extends only to copyright in the software and shall
610801Srene.dejong@arm.com * not be construed as granting a license to any other intellectual
710801Srene.dejong@arm.com * property including but not limited to intellectual property relating
810801Srene.dejong@arm.com * to a hardware implementation of the functionality of the software
910801Srene.dejong@arm.com * licensed hereunder.  You may use the software subject to the license
1010801Srene.dejong@arm.com * terms below provided that you ensure that this notice is replicated
1110801Srene.dejong@arm.com * unmodified and in its entirety in all distributions of the software,
1210801Srene.dejong@arm.com * modified or unmodified, in source code or in binary form.
1310801Srene.dejong@arm.com *
1410801Srene.dejong@arm.com * Redistribution and use in source and binary forms, with or without
1510801Srene.dejong@arm.com * modification, are permitted provided that the following conditions are
1610801Srene.dejong@arm.com * met: redistributions of source code must retain the above copyright
1710801Srene.dejong@arm.com * notice, this list of conditions and the following disclaimer;
1810801Srene.dejong@arm.com * redistributions in binary form must reproduce the above copyright
1910801Srene.dejong@arm.com * notice, this list of conditions and the following disclaimer in the
2010801Srene.dejong@arm.com * documentation and/or other materials provided with the distribution;
2110801Srene.dejong@arm.com * neither the name of the copyright holders nor the names of its
2210801Srene.dejong@arm.com * contributors may be used to endorse or promote products derived from
2310801Srene.dejong@arm.com * this software without specific prior written permission.
2410801Srene.dejong@arm.com *
2510801Srene.dejong@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610801Srene.dejong@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710801Srene.dejong@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810801Srene.dejong@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910801Srene.dejong@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010801Srene.dejong@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110801Srene.dejong@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210801Srene.dejong@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310801Srene.dejong@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410801Srene.dejong@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510801Srene.dejong@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610801Srene.dejong@arm.com *
3710801Srene.dejong@arm.com * Authors: Rene de Jong
3810801Srene.dejong@arm.com */
3910801Srene.dejong@arm.com
4010801Srene.dejong@arm.com/** @file
4110801Srene.dejong@arm.com * This simplistic flash model is designed to model managed SLC NAND flash.
4210801Srene.dejong@arm.com * This device will need an interface module (such as NVMe or UFS); Note that
4310801Srene.dejong@arm.com * this model only calculates the delay and does not perform the actual
4410801Srene.dejong@arm.com * transaction.
4510801Srene.dejong@arm.com *
4610801Srene.dejong@arm.com * To access the memory, use either readMemory or writeMemory. This will
4710801Srene.dejong@arm.com * schedule an event at the tick where the action will finish. If a callback
4810801Srene.dejong@arm.com * has been given as argument then that function will be called on completion
4910801Srene.dejong@arm.com * of that event. Note that this does not guarantee that there are no other
5010801Srene.dejong@arm.com * actions pending in the flash device.
5110801Srene.dejong@arm.com *
5210801Srene.dejong@arm.com * IMPORTANT: number of planes should be a power of 2.
5310801Srene.dejong@arm.com */
5410801Srene.dejong@arm.com
5510801Srene.dejong@arm.com#include "dev/arm/flash_device.hh"
5610801Srene.dejong@arm.com
5710801Srene.dejong@arm.com#include "debug/Drain.hh"
5810801Srene.dejong@arm.com
5910801Srene.dejong@arm.com/**
6010801Srene.dejong@arm.com * Create this device
6110801Srene.dejong@arm.com */
6210801Srene.dejong@arm.com
6310801Srene.dejong@arm.comFlashDevice*
6410801Srene.dejong@arm.comFlashDeviceParams::create()
6510801Srene.dejong@arm.com{
6610801Srene.dejong@arm.com    return new FlashDevice(this);
6710801Srene.dejong@arm.com}
6810801Srene.dejong@arm.com
6910801Srene.dejong@arm.com
7010801Srene.dejong@arm.com/**
7110801Srene.dejong@arm.com * Flash Device constructor and destructor
7210801Srene.dejong@arm.com */
7310801Srene.dejong@arm.com
7410801Srene.dejong@arm.comFlashDevice::FlashDevice(const FlashDeviceParams* p):
7510801Srene.dejong@arm.com    AbstractNVM(p),
7610801Srene.dejong@arm.com    diskSize(0),
7710801Srene.dejong@arm.com    blockSize(p->blk_size),
7810801Srene.dejong@arm.com    pageSize(p->page_size),
7910801Srene.dejong@arm.com    GCActivePercentage(p->GC_active),
8010801Srene.dejong@arm.com    readLatency(p->read_lat),
8110801Srene.dejong@arm.com    writeLatency(p->write_lat),
8210801Srene.dejong@arm.com    eraseLatency(p->erase_lat),
8310801Srene.dejong@arm.com    dataDistribution(p->data_distribution),
8410801Srene.dejong@arm.com    numPlanes(p->num_planes),
8510801Srene.dejong@arm.com    pagesPerBlock(0),
8610801Srene.dejong@arm.com    pagesPerDisk(0),
8710801Srene.dejong@arm.com    blocksPerDisk(0),
8810801Srene.dejong@arm.com    planeMask(numPlanes - 1),
8910801Srene.dejong@arm.com    planeEventQueue(numPlanes),
9010801Srene.dejong@arm.com    planeEvent(this)
9110801Srene.dejong@arm.com{
9210801Srene.dejong@arm.com
9310801Srene.dejong@arm.com    /*
9410801Srene.dejong@arm.com     * Let 'a' be a power of two of n bits, written such that a-n is the msb
9510801Srene.dejong@arm.com     * and a-0 is the lsb. Since it is a power of two, only one bit (a-x,
9610801Srene.dejong@arm.com     * with 0 <= x <= n) is set. If we subtract one from this number the bits
9710801Srene.dejong@arm.com     * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a
9810801Srene.dejong@arm.com     * bitwise AND with those two numbers results in an integer with all bits
9910801Srene.dejong@arm.com     * cleared.
10010801Srene.dejong@arm.com     */
10111321Ssteve.reinhardt@amd.com    if (numPlanes & planeMask)
10210801Srene.dejong@arm.com        fatal("Number of planes is not a power of 2 in flash device.\n");
10310801Srene.dejong@arm.com}
10410801Srene.dejong@arm.com
10510801Srene.dejong@arm.com/**
10610801Srene.dejong@arm.com * Initiates all the flash functions: initializes the lookup tables, age of
10710801Srene.dejong@arm.com * the device, etc. This can only be done once the disk image is known.
10810801Srene.dejong@arm.com * Thats why it can't be done in the constructor.
10910801Srene.dejong@arm.com */
11010801Srene.dejong@arm.comvoid
11110801Srene.dejong@arm.comFlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size)
11210801Srene.dejong@arm.com{
11310801Srene.dejong@arm.com    diskSize = disk_size * sector_size;
11410801Srene.dejong@arm.com    pagesPerBlock = blockSize / pageSize;
11510801Srene.dejong@arm.com    pagesPerDisk = diskSize / pageSize;
11610801Srene.dejong@arm.com    blocksPerDisk = diskSize / blockSize;
11710801Srene.dejong@arm.com
11810801Srene.dejong@arm.com    /** Sanity information: check flash configuration */
11910801Srene.dejong@arm.com    DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages "
12010801Srene.dejong@arm.com            "per disk\n", diskSize, pagesPerBlock, pagesPerDisk);
12110801Srene.dejong@arm.com
12210801Srene.dejong@arm.com    locationTable.resize(pagesPerDisk);
12310801Srene.dejong@arm.com
12410801Srene.dejong@arm.com    /**Garbage collection related*/
12510801Srene.dejong@arm.com    blockValidEntries.resize(blocksPerDisk, 0);
12610801Srene.dejong@arm.com    blockEmptyEntries.resize(blocksPerDisk, pagesPerBlock);
12710801Srene.dejong@arm.com
12810801Srene.dejong@arm.com    /**
12910801Srene.dejong@arm.com     * This is a bitmap. Every bit is a page
13010801Srene.dejong@arm.com     * unknownPages is a vector of 32 bit integers. If every page was an
13110801Srene.dejong@arm.com     * integer, the total size would be pagesPerDisk; since we can map one
13210801Srene.dejong@arm.com     * page per bit we need ceil(pagesPerDisk/32) entries. 32 = 1 << 5 hence
13310801Srene.dejong@arm.com     * it will do to just shift pagesPerDisk five positions and add one. This
13410801Srene.dejong@arm.com     * will allocate one integer to many for this data structure in the worst
13510801Srene.dejong@arm.com     * case.
13610801Srene.dejong@arm.com     */
13710801Srene.dejong@arm.com    unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF);
13810801Srene.dejong@arm.com
13910801Srene.dejong@arm.com    for (uint32_t count = 0; count < pagesPerDisk; count++) {
14010801Srene.dejong@arm.com        //setup lookup table + physical aspects
14110801Srene.dejong@arm.com
14210801Srene.dejong@arm.com        if (dataDistribution == Enums::stripe) {
14310801Srene.dejong@arm.com            locationTable[count].page = count / blocksPerDisk;
14410801Srene.dejong@arm.com            locationTable[count].block = count % blocksPerDisk;
14510801Srene.dejong@arm.com
14610801Srene.dejong@arm.com        } else {
14710801Srene.dejong@arm.com            locationTable[count].page = count % pagesPerBlock;
14810801Srene.dejong@arm.com            locationTable[count].block = count / pagesPerBlock;
14910801Srene.dejong@arm.com        }
15010801Srene.dejong@arm.com    }
15110801Srene.dejong@arm.com}
15210801Srene.dejong@arm.com
15310801Srene.dejong@arm.comFlashDevice::~FlashDevice()
15410801Srene.dejong@arm.com{
15510801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Remove FlashDevice\n");
15610801Srene.dejong@arm.com}
15710801Srene.dejong@arm.com
15810801Srene.dejong@arm.com/**
15910801Srene.dejong@arm.com * Handles the accesses to the device.
16010801Srene.dejong@arm.com * The function determines when certain actions are scheduled and schedules
16110801Srene.dejong@arm.com * an event that uses the callback function on completion of the action.
16210801Srene.dejong@arm.com */
16310801Srene.dejong@arm.comvoid
16410801Srene.dejong@arm.comFlashDevice::accessDevice(uint64_t address, uint32_t amount, Callback *event,
16510801Srene.dejong@arm.com                          Actions action)
16610801Srene.dejong@arm.com{
16710801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n"
16810801Srene.dejong@arm.com            , amount, pageSize);
16910801Srene.dejong@arm.com
17010801Srene.dejong@arm.com    std::vector<Tick> time(numPlanes, 0);
17110801Srene.dejong@arm.com    uint64_t logic_page_addr = address / pageSize;
17210801Srene.dejong@arm.com    uint32_t plane_address = 0;
17310801Srene.dejong@arm.com
17410801Srene.dejong@arm.com    /**
17510801Srene.dejong@arm.com     * The access will be broken up in a number of page accesses. The number
17610801Srene.dejong@arm.com     * of page accesses depends on the amount that needs to be transfered.
17710801Srene.dejong@arm.com     * The assumption here is that the interface is completely ignorant of
17810801Srene.dejong@arm.com     * the page size and that this model has to figure out all of the
17910801Srene.dejong@arm.com     * transaction characteristics.
18010801Srene.dejong@arm.com     */
18110801Srene.dejong@arm.com    for (uint32_t count = 0; amount > (count * pageSize); count++) {
18210801Srene.dejong@arm.com        uint32_t index = (locationTable[logic_page_addr].block *
18310801Srene.dejong@arm.com                          pagesPerBlock) + (logic_page_addr % pagesPerBlock);
18410801Srene.dejong@arm.com
18510801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d,"
18610801Srene.dejong@arm.com                " logic address 0x%8x\n", index,
18710801Srene.dejong@arm.com                locationTable[logic_page_addr].block, pagesPerBlock,
18810801Srene.dejong@arm.com                logic_page_addr);
18910801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count,
19010801Srene.dejong@arm.com                (count * pageSize));
19110801Srene.dejong@arm.com
19210801Srene.dejong@arm.com        plane_address = locationTable[logic_page_addr].block & planeMask;
19310801Srene.dejong@arm.com
19410801Srene.dejong@arm.com        if (action == ActionRead) {
19510801Srene.dejong@arm.com            //lookup
19610801Srene.dejong@arm.com            //call accessTimes
19710801Srene.dejong@arm.com            time[plane_address] += accessTimes(locationTable[logic_page_addr]
19810801Srene.dejong@arm.com                                               .block, ActionRead);
19910801Srene.dejong@arm.com
20010801Srene.dejong@arm.com            /*stats*/
20110801Srene.dejong@arm.com            stats.readAccess.sample(logic_page_addr);
20210801Srene.dejong@arm.com            stats.readLatency.sample(time[plane_address]);
20310801Srene.dejong@arm.com        } else { //write
20410801Srene.dejong@arm.com            //lookup
20510801Srene.dejong@arm.com            //call accessTimes if appropriate, page may be unknown, so lets
20610801Srene.dejong@arm.com            //give it the benefit of the doubt
20710801Srene.dejong@arm.com
20810801Srene.dejong@arm.com            if (getUnknownPages(index))
20910801Srene.dejong@arm.com                time[plane_address] += accessTimes
21010801Srene.dejong@arm.com                    (locationTable[logic_page_addr].block, ActionWrite);
21110801Srene.dejong@arm.com
21210801Srene.dejong@arm.com            else //A remap is needed
21310801Srene.dejong@arm.com                time[plane_address] += remap(logic_page_addr);
21410801Srene.dejong@arm.com
21510801Srene.dejong@arm.com            /*stats*/
21610801Srene.dejong@arm.com            stats.writeAccess.sample(logic_page_addr);
21710801Srene.dejong@arm.com            stats.writeLatency.sample(time[plane_address]);
21810801Srene.dejong@arm.com        }
21910801Srene.dejong@arm.com
22010801Srene.dejong@arm.com        /**
22110801Srene.dejong@arm.com         * Check if the page is known and used. unknownPages is a bitmap of
22210801Srene.dejong@arm.com         * all the pages. It tracks wether we can be sure that the
22310801Srene.dejong@arm.com         * information of this page is taken into acount in the model (is it
22410801Srene.dejong@arm.com         * considered in blockValidEntries and blockEmptyEntries?). If it has
22510801Srene.dejong@arm.com         * been used in the past, then it is known.
22610801Srene.dejong@arm.com         */
22710801Srene.dejong@arm.com        if (getUnknownPages(index)) {
22810801Srene.dejong@arm.com            clearUnknownPages(index);
22910801Srene.dejong@arm.com            --blockEmptyEntries[locationTable[logic_page_addr].block];
23010801Srene.dejong@arm.com            ++blockValidEntries[locationTable[logic_page_addr].block];
23110801Srene.dejong@arm.com        }
23210801Srene.dejong@arm.com
23310801Srene.dejong@arm.com        stats.fileSystemAccess.sample(address);
23410801Srene.dejong@arm.com        ++logic_page_addr;
23510801Srene.dejong@arm.com    }
23610801Srene.dejong@arm.com
23710801Srene.dejong@arm.com    /**
23810801Srene.dejong@arm.com     * previous part of the function found the times spend in different
23910801Srene.dejong@arm.com     * planes, now lets find the maximum to know when to callback the disk
24010801Srene.dejong@arm.com     */
24110801Srene.dejong@arm.com    for (uint32_t count = 0; count < numPlanes; count++){
24210801Srene.dejong@arm.com        plane_address = (time[plane_address] > time[count]) ? plane_address
24310801Srene.dejong@arm.com            : count;
24410801Srene.dejong@arm.com
24510801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count,
24610801Srene.dejong@arm.com                time[count]);
24710801Srene.dejong@arm.com
24811321Ssteve.reinhardt@amd.com        if (time[count] != 0) {
24910801Srene.dejong@arm.com
25010801Srene.dejong@arm.com            struct CallBackEntry cbe;
25110801Srene.dejong@arm.com            /**
25210801Srene.dejong@arm.com             * If there are no events for this plane, then add the current
25310801Srene.dejong@arm.com             * time to the occupation time; otherwise, plan it after the
25410801Srene.dejong@arm.com             * last event. If by chance that event is handled in this tick,
25510801Srene.dejong@arm.com             * then we would still end up with the same result.
25610801Srene.dejong@arm.com             */
25710801Srene.dejong@arm.com            if (planeEventQueue[count].empty())
25810801Srene.dejong@arm.com                cbe.time = time[count] + curTick();
25910801Srene.dejong@arm.com            else
26010801Srene.dejong@arm.com                cbe.time = time[count] +
26110801Srene.dejong@arm.com                           planeEventQueue[count].back().time;
26210801Srene.dejong@arm.com            cbe.function = NULL;
26310801Srene.dejong@arm.com            planeEventQueue[count].push_back(cbe);
26410801Srene.dejong@arm.com
26510801Srene.dejong@arm.com            DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time);
26610801Srene.dejong@arm.com
26710801Srene.dejong@arm.com            if (!planeEvent.scheduled())
26810801Srene.dejong@arm.com                schedule(planeEvent, planeEventQueue[count].back().time);
26910801Srene.dejong@arm.com            else if (planeEventQueue[count].back().time < planeEvent.when())
27010801Srene.dejong@arm.com                reschedule(planeEvent,
27110801Srene.dejong@arm.com                    planeEventQueue[plane_address].back().time, true);
27210801Srene.dejong@arm.com        }
27310801Srene.dejong@arm.com    }
27410801Srene.dejong@arm.com
27510801Srene.dejong@arm.com    //worst case two plane finish at the same time, each triggers an event
27610801Srene.dejong@arm.com    //and this callback will be called once. Maybe before the other plane
27710801Srene.dejong@arm.com    //could execute its event, but in the same tick.
27810801Srene.dejong@arm.com    planeEventQueue[plane_address].back().function = event;
27910801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n",
28010801Srene.dejong@arm.com            plane_address, planeEventQueue[plane_address].size());
28110801Srene.dejong@arm.com    DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
28210801Srene.dejong@arm.com}
28310801Srene.dejong@arm.com
28410801Srene.dejong@arm.com/**
28510801Srene.dejong@arm.com * When a plane completes its action, this event is triggered. When a
28610801Srene.dejong@arm.com * callback function was associated with that event, it will be called.
28710801Srene.dejong@arm.com */
28810801Srene.dejong@arm.com
28910801Srene.dejong@arm.comvoid
29010801Srene.dejong@arm.comFlashDevice::actionComplete()
29110801Srene.dejong@arm.com{
29210801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Plane action completed\n");
29310801Srene.dejong@arm.com    uint8_t plane_address = 0;
29410801Srene.dejong@arm.com
29510801Srene.dejong@arm.com    uint8_t next_event = 0;
29610801Srene.dejong@arm.com
29710801Srene.dejong@arm.com    /**Search for a callback that is supposed to happen in this Tick*/
29810801Srene.dejong@arm.com    for (plane_address = 0; plane_address < numPlanes; plane_address++) {
29910801Srene.dejong@arm.com        if (!planeEventQueue[plane_address].empty()) {
30010801Srene.dejong@arm.com            /**
30110801Srene.dejong@arm.com             * Invariant: All queued events are scheduled in the present
30210801Srene.dejong@arm.com             *  or future.
30310801Srene.dejong@arm.com             */
30410801Srene.dejong@arm.com            assert(planeEventQueue[plane_address].front().time >= curTick());
30510801Srene.dejong@arm.com
30610801Srene.dejong@arm.com            if (planeEventQueue[plane_address].front().time == curTick()) {
30710801Srene.dejong@arm.com                /**
30810801Srene.dejong@arm.com                 * To ensure that the follow-up action is executed correctly,
30910801Srene.dejong@arm.com                 * the callback entry first need to be cleared before it can
31010801Srene.dejong@arm.com                 * be called.
31110801Srene.dejong@arm.com                 */
31210801Srene.dejong@arm.com                Callback *temp = planeEventQueue[plane_address].front().
31310801Srene.dejong@arm.com                                 function;
31410801Srene.dejong@arm.com                planeEventQueue[plane_address].pop_front();
31510801Srene.dejong@arm.com
31610801Srene.dejong@arm.com                /**Found a callback, lets make it happen*/
31710801Srene.dejong@arm.com                if (temp != NULL) {
31810801Srene.dejong@arm.com                    DPRINTF(FlashDevice, "Callback, %d\n", plane_address);
31910801Srene.dejong@arm.com                    temp->process();
32010801Srene.dejong@arm.com                }
32110801Srene.dejong@arm.com            }
32210801Srene.dejong@arm.com        }
32310801Srene.dejong@arm.com    }
32410801Srene.dejong@arm.com
32510801Srene.dejong@arm.com    /** Find when to schedule the planeEvent next */
32610801Srene.dejong@arm.com    for (plane_address = 0; plane_address < numPlanes; plane_address++) {
32710801Srene.dejong@arm.com        if (!planeEventQueue[plane_address].empty())
32810801Srene.dejong@arm.com            if (planeEventQueue[next_event].empty() ||
32910801Srene.dejong@arm.com                    (planeEventQueue[plane_address].front().time <
33010801Srene.dejong@arm.com                     planeEventQueue[next_event].front().time))
33110801Srene.dejong@arm.com                next_event = plane_address;
33210801Srene.dejong@arm.com    }
33310801Srene.dejong@arm.com
33410801Srene.dejong@arm.com    /**Schedule the next plane that will be ready (if any)*/
33510801Srene.dejong@arm.com    if (!planeEventQueue[next_event].empty()) {
33610801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address);
33710801Srene.dejong@arm.com        reschedule(planeEvent, planeEventQueue[next_event].front().time, true);
33810801Srene.dejong@arm.com    }
33910801Srene.dejong@arm.com
34010801Srene.dejong@arm.com    checkDrain();
34110801Srene.dejong@arm.com
34210801Srene.dejong@arm.com    DPRINTF(FlashDevice, "returing from flash event\n");
34310801Srene.dejong@arm.com    DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
34410801Srene.dejong@arm.com}
34510801Srene.dejong@arm.com
34610801Srene.dejong@arm.com/**
34710801Srene.dejong@arm.com * Handles the remapping of the pages. It is a (I hope) sensible statistic
34810801Srene.dejong@arm.com * approach. asumption: garbage collection happens when a clean is needed
34910801Srene.dejong@arm.com * (may become stochastic function).
35010801Srene.dejong@arm.com */
35110801Srene.dejong@arm.comTick
35210801Srene.dejong@arm.comFlashDevice::remap(uint64_t logic_page_addr)
35310801Srene.dejong@arm.com{
35410801Srene.dejong@arm.com    /**
35510801Srene.dejong@arm.com     * Are there any empty left in this Block, or do we need to do an erase
35610801Srene.dejong@arm.com     */
35710801Srene.dejong@arm.com    if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) {
35810801Srene.dejong@arm.com        //just a remap
35910801Srene.dejong@arm.com        //update tables
36010801Srene.dejong@arm.com        --blockEmptyEntries[locationTable[logic_page_addr].block];
36110801Srene.dejong@arm.com        //access to this table won't be sequential anymore
36210801Srene.dejong@arm.com        locationTable[logic_page_addr].page = pagesPerBlock + 2;
36310801Srene.dejong@arm.com        //access new block
36410801Srene.dejong@arm.com        Tick time = accessTimes(locationTable[logic_page_addr].block,
36510801Srene.dejong@arm.com                                ActionWrite);
36610801Srene.dejong@arm.com
36710801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Remap returns %d ticks\n", time);
36810801Srene.dejong@arm.com        return time;
36910801Srene.dejong@arm.com
37010801Srene.dejong@arm.com    } else {
37110801Srene.dejong@arm.com        //calculate how much time GC would have taken
37210801Srene.dejong@arm.com        uint32_t block = locationTable[logic_page_addr].block;
37310801Srene.dejong@arm.com        Tick time = ((GCActivePercentage *
37410801Srene.dejong@arm.com                       (accessTimes(block, ActionCopy) +
37510801Srene.dejong@arm.com                        accessTimes(block, ActionErase)))
37610801Srene.dejong@arm.com                     / 100);
37710801Srene.dejong@arm.com
37810801Srene.dejong@arm.com        //use block as the logical start address of the block
37910801Srene.dejong@arm.com        block = locationTable[logic_page_addr].block * pagesPerBlock;
38010801Srene.dejong@arm.com
38110801Srene.dejong@arm.com        //assumption: clean will improve locality
38211180Ssascha.bischoff@ARM.com        for (uint32_t count = 0; count < pagesPerBlock; count++) {
38311180Ssascha.bischoff@ARM.com            assert(block + count < pagesPerDisk);
38410801Srene.dejong@arm.com            locationTable[block + count].page = (block + count) %
38510801Srene.dejong@arm.com                pagesPerBlock;
38610801Srene.dejong@arm.com        }
38710801Srene.dejong@arm.com
38810801Srene.dejong@arm.com        blockEmptyEntries[locationTable[logic_page_addr].block] =
38910801Srene.dejong@arm.com            pagesPerBlock;
39010801Srene.dejong@arm.com        /*stats*/
39110801Srene.dejong@arm.com        ++stats.totalGCActivations;
39210801Srene.dejong@arm.com
39310801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n",
39410801Srene.dejong@arm.com                time);
39510801Srene.dejong@arm.com
39610801Srene.dejong@arm.com        return time;
39710801Srene.dejong@arm.com    }
39810801Srene.dejong@arm.com
39910801Srene.dejong@arm.com}
40010801Srene.dejong@arm.com
40110801Srene.dejong@arm.com/**
40210801Srene.dejong@arm.com * Calculates the accesstime per operation needed
40310801Srene.dejong@arm.com */
40410801Srene.dejong@arm.comTick
40510801Srene.dejong@arm.comFlashDevice::accessTimes(uint64_t block, Actions action)
40610801Srene.dejong@arm.com{
40710801Srene.dejong@arm.com    Tick time = 0;
40810801Srene.dejong@arm.com
40910801Srene.dejong@arm.com    switch(action) {
41010801Srene.dejong@arm.com      case ActionRead: {
41110801Srene.dejong@arm.com          /**Just read the page*/
41210801Srene.dejong@arm.com          time = readLatency;
41310801Srene.dejong@arm.com      } break;
41410801Srene.dejong@arm.com
41510801Srene.dejong@arm.com      case ActionWrite: {
41610801Srene.dejong@arm.com          /**Write the page, and read the result*/
41710801Srene.dejong@arm.com          time = writeLatency + readLatency;
41810801Srene.dejong@arm.com      } break;
41910801Srene.dejong@arm.com
42010801Srene.dejong@arm.com      case ActionErase: {
42110801Srene.dejong@arm.com          /**Erase and check wether it was successfull*/
42210801Srene.dejong@arm.com          time = eraseLatency + readLatency;
42310801Srene.dejong@arm.com      } break;
42410801Srene.dejong@arm.com
42510801Srene.dejong@arm.com      case ActionCopy: {
42610801Srene.dejong@arm.com          /**Copy every valid page*/
42710801Srene.dejong@arm.com          uint32_t validpages = blockValidEntries[block];
42810801Srene.dejong@arm.com          time = validpages * (readLatency + writeLatency);
42910801Srene.dejong@arm.com      } break;
43010801Srene.dejong@arm.com
43110801Srene.dejong@arm.com      default: break;
43210801Srene.dejong@arm.com    }
43310801Srene.dejong@arm.com
43410801Srene.dejong@arm.com    //Used to determine sequential action.
43510801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Access returns %d ticks\n", time);
43610801Srene.dejong@arm.com    return time;
43710801Srene.dejong@arm.com}
43810801Srene.dejong@arm.com
43910801Srene.dejong@arm.com/**
44010801Srene.dejong@arm.com * clearUnknownPages. defines that a page is known and used
44110801Srene.dejong@arm.com * unknownPages is a bitmap of all the pages. It tracks wether we can be sure
44210801Srene.dejong@arm.com * that the information of this page is taken into acount in the model (is it
44310801Srene.dejong@arm.com * considered in blockValidEntries and blockEmptyEntries?). If it has been
44410801Srene.dejong@arm.com * used in the past, then it is known. But it needs to be tracked to make
44510801Srene.dejong@arm.com * decisions about write accesses, and indirectly about copy actions. one
44610801Srene.dejong@arm.com * unknownPage entry is a 32 bit integer. So if we have a page index, then
44710801Srene.dejong@arm.com * that means that we need entry floor(index/32) (index >> 5) and we need to
44810801Srene.dejong@arm.com * select the bit which number is equal to the remainder of index/32
44910801Srene.dejong@arm.com * (index%32). The bit is cleared to make sure that we see it as considered
45010801Srene.dejong@arm.com * in the future.
45110801Srene.dejong@arm.com */
45210801Srene.dejong@arm.com
45310801Srene.dejong@arm.cominline
45410801Srene.dejong@arm.comvoid
45510801Srene.dejong@arm.comFlashDevice::clearUnknownPages(uint32_t index)
45610801Srene.dejong@arm.com{
45710801Srene.dejong@arm.com    unknownPages[index >> 5] &= ~(0x01 << (index % 32));
45810801Srene.dejong@arm.com}
45910801Srene.dejong@arm.com
46010801Srene.dejong@arm.com/**
46110801Srene.dejong@arm.com * getUnknownPages. Verify wether a page is known
46210801Srene.dejong@arm.com */
46310801Srene.dejong@arm.com
46410801Srene.dejong@arm.cominline
46510801Srene.dejong@arm.combool
46610801Srene.dejong@arm.comFlashDevice::getUnknownPages(uint32_t index)
46710801Srene.dejong@arm.com{
46810801Srene.dejong@arm.com    return unknownPages[index >> 5] & (0x01 << (index % 32));
46910801Srene.dejong@arm.com}
47010801Srene.dejong@arm.com
47110801Srene.dejong@arm.comvoid
47210801Srene.dejong@arm.comFlashDevice::regStats()
47310801Srene.dejong@arm.com{
47411523Sdavid.guillen@arm.com    AbstractNVM::regStats();
47511523Sdavid.guillen@arm.com
47610801Srene.dejong@arm.com    using namespace Stats;
47710801Srene.dejong@arm.com
47810801Srene.dejong@arm.com    std::string fd_name = name() + ".FlashDevice";
47910801Srene.dejong@arm.com
48010801Srene.dejong@arm.com    // Register the stats
48110801Srene.dejong@arm.com    /** Amount of GC activations*/
48210801Srene.dejong@arm.com    stats.totalGCActivations
48310801Srene.dejong@arm.com        .name(fd_name + ".totalGCActivations")
48410801Srene.dejong@arm.com        .desc("Number of Garbage collector activations")
48510801Srene.dejong@arm.com        .flags(none);
48610801Srene.dejong@arm.com
48710801Srene.dejong@arm.com    /** Histogram of address accesses*/
48810801Srene.dejong@arm.com    stats.writeAccess
48910801Srene.dejong@arm.com        .init(2)
49010801Srene.dejong@arm.com        .name(fd_name + ".writeAccessHist")
49110801Srene.dejong@arm.com        .desc("Histogram of write addresses")
49210801Srene.dejong@arm.com        .flags(pdf);
49310801Srene.dejong@arm.com    stats.readAccess
49410801Srene.dejong@arm.com        .init(2)
49510801Srene.dejong@arm.com        .name(fd_name + ".readAccessHist")
49610801Srene.dejong@arm.com        .desc("Histogram of read addresses")
49710801Srene.dejong@arm.com        .flags(pdf);
49810801Srene.dejong@arm.com    stats.fileSystemAccess
49910801Srene.dejong@arm.com        .init(100)
50010801Srene.dejong@arm.com        .name(fd_name + ".fileSystemAccessHist")
50110801Srene.dejong@arm.com        .desc("Histogram of file system accesses")
50210801Srene.dejong@arm.com        .flags(pdf);
50310801Srene.dejong@arm.com
50410801Srene.dejong@arm.com    /** Histogram of access latencies*/
50510801Srene.dejong@arm.com    stats.writeLatency
50610801Srene.dejong@arm.com        .init(100)
50710801Srene.dejong@arm.com        .name(fd_name + ".writeLatencyHist")
50810801Srene.dejong@arm.com        .desc("Histogram of write latency")
50910801Srene.dejong@arm.com        .flags(pdf);
51010801Srene.dejong@arm.com    stats.readLatency
51110801Srene.dejong@arm.com        .init(100)
51210801Srene.dejong@arm.com        .name(fd_name + ".readLatencyHist")
51310801Srene.dejong@arm.com        .desc("Histogram of read latency")
51410801Srene.dejong@arm.com        .flags(pdf);
51510801Srene.dejong@arm.com}
51610801Srene.dejong@arm.com
51710801Srene.dejong@arm.com/**
51810801Srene.dejong@arm.com * Serialize; needed to create checkpoints
51910801Srene.dejong@arm.com */
52010801Srene.dejong@arm.com
52110801Srene.dejong@arm.comvoid
52210905Sandreas.sandberg@arm.comFlashDevice::serialize(CheckpointOut &cp) const
52310801Srene.dejong@arm.com{
52410801Srene.dejong@arm.com    SERIALIZE_SCALAR(planeMask);
52510801Srene.dejong@arm.com
52611226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(unknownPages);
52711226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(blockValidEntries);
52811226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(blockEmptyEntries);
52910801Srene.dejong@arm.com
53010801Srene.dejong@arm.com    int location_table_size = locationTable.size();
53110801Srene.dejong@arm.com    SERIALIZE_SCALAR(location_table_size);
53210801Srene.dejong@arm.com    for (uint32_t count = 0; count < location_table_size; count++) {
53311226SGeoffrey.Blake@arm.com        paramOut(cp, csprintf("locationTable[%d].page", count),
53411226SGeoffrey.Blake@arm.com                 locationTable[count].page);
53511226SGeoffrey.Blake@arm.com        paramOut(cp, csprintf("locationTable[%d].block", count),
53611226SGeoffrey.Blake@arm.com                 locationTable[count].block);
53711226SGeoffrey.Blake@arm.com    }
53810801Srene.dejong@arm.com};
53910801Srene.dejong@arm.com
54010801Srene.dejong@arm.com/**
54110801Srene.dejong@arm.com * Unserialize; needed to restore from checkpoints
54210801Srene.dejong@arm.com */
54310801Srene.dejong@arm.com
54410801Srene.dejong@arm.comvoid
54510905Sandreas.sandberg@arm.comFlashDevice::unserialize(CheckpointIn &cp)
54610801Srene.dejong@arm.com{
54710801Srene.dejong@arm.com    UNSERIALIZE_SCALAR(planeMask);
54810801Srene.dejong@arm.com
54911226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(unknownPages);
55011226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(blockValidEntries);
55111226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(blockEmptyEntries);
55210801Srene.dejong@arm.com
55310801Srene.dejong@arm.com    int location_table_size;
55410801Srene.dejong@arm.com    UNSERIALIZE_SCALAR(location_table_size);
55510801Srene.dejong@arm.com    locationTable.resize(location_table_size);
55610801Srene.dejong@arm.com    for (uint32_t count = 0; count < location_table_size; count++) {
55711226SGeoffrey.Blake@arm.com        paramIn(cp, csprintf("locationTable[%d].page", count),
55811226SGeoffrey.Blake@arm.com                locationTable[count].page);
55911226SGeoffrey.Blake@arm.com        paramIn(cp, csprintf("locationTable[%d].block", count),
56011226SGeoffrey.Blake@arm.com                locationTable[count].block);
56111226SGeoffrey.Blake@arm.com    }
56210801Srene.dejong@arm.com};
56310801Srene.dejong@arm.com
56410801Srene.dejong@arm.com/**
56510801Srene.dejong@arm.com * Drain; needed to enable checkpoints
56610801Srene.dejong@arm.com */
56710801Srene.dejong@arm.com
56810913Sandreas.sandberg@arm.comDrainState
56910913Sandreas.sandberg@arm.comFlashDevice::drain()
57010801Srene.dejong@arm.com{
57110801Srene.dejong@arm.com    if (planeEvent.scheduled()) {
57210913Sandreas.sandberg@arm.com        DPRINTF(Drain, "Flash device is draining...\n");
57310913Sandreas.sandberg@arm.com        return DrainState::Draining;
57410801Srene.dejong@arm.com    } else {
57510801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device in drained state\n");
57610913Sandreas.sandberg@arm.com        return DrainState::Drained;
57710801Srene.dejong@arm.com    }
57810801Srene.dejong@arm.com}
57910801Srene.dejong@arm.com
58010801Srene.dejong@arm.com/**
58110801Srene.dejong@arm.com * Checkdrain; needed to enable checkpoints
58210801Srene.dejong@arm.com */
58310801Srene.dejong@arm.com
58410801Srene.dejong@arm.comvoid
58510801Srene.dejong@arm.comFlashDevice::checkDrain()
58610801Srene.dejong@arm.com{
58711179Ssascha.bischoff@ARM.com    if (drainState() != DrainState::Draining)
58810801Srene.dejong@arm.com        return;
58910801Srene.dejong@arm.com
59010801Srene.dejong@arm.com    if (planeEvent.when() > curTick()) {
59110801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device is still draining\n");
59210801Srene.dejong@arm.com    } else {
59310801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device is done draining\n");
59410913Sandreas.sandberg@arm.com        signalDrainDone();
59510801Srene.dejong@arm.com    }
59610801Srene.dejong@arm.com}
597