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
5711800Sbrandon.potter@amd.com#include "base/trace.hh"
5810801Srene.dejong@arm.com#include "debug/Drain.hh"
5910801Srene.dejong@arm.com
6010801Srene.dejong@arm.com/**
6110801Srene.dejong@arm.com * Create this device
6210801Srene.dejong@arm.com */
6310801Srene.dejong@arm.com
6410801Srene.dejong@arm.comFlashDevice*
6510801Srene.dejong@arm.comFlashDeviceParams::create()
6610801Srene.dejong@arm.com{
6710801Srene.dejong@arm.com    return new FlashDevice(this);
6810801Srene.dejong@arm.com}
6910801Srene.dejong@arm.com
7010801Srene.dejong@arm.com
7110801Srene.dejong@arm.com/**
7210801Srene.dejong@arm.com * Flash Device constructor and destructor
7310801Srene.dejong@arm.com */
7410801Srene.dejong@arm.com
7510801Srene.dejong@arm.comFlashDevice::FlashDevice(const FlashDeviceParams* p):
7610801Srene.dejong@arm.com    AbstractNVM(p),
7710801Srene.dejong@arm.com    diskSize(0),
7810801Srene.dejong@arm.com    blockSize(p->blk_size),
7910801Srene.dejong@arm.com    pageSize(p->page_size),
8010801Srene.dejong@arm.com    GCActivePercentage(p->GC_active),
8110801Srene.dejong@arm.com    readLatency(p->read_lat),
8210801Srene.dejong@arm.com    writeLatency(p->write_lat),
8310801Srene.dejong@arm.com    eraseLatency(p->erase_lat),
8410801Srene.dejong@arm.com    dataDistribution(p->data_distribution),
8510801Srene.dejong@arm.com    numPlanes(p->num_planes),
8610801Srene.dejong@arm.com    pagesPerBlock(0),
8710801Srene.dejong@arm.com    pagesPerDisk(0),
8810801Srene.dejong@arm.com    blocksPerDisk(0),
8910801Srene.dejong@arm.com    planeMask(numPlanes - 1),
9010801Srene.dejong@arm.com    planeEventQueue(numPlanes),
9112086Sspwilson2@wisc.edu    planeEvent([this]{ actionComplete(); }, name())
9210801Srene.dejong@arm.com{
9310801Srene.dejong@arm.com
9410801Srene.dejong@arm.com    /*
9510801Srene.dejong@arm.com     * Let 'a' be a power of two of n bits, written such that a-n is the msb
9610801Srene.dejong@arm.com     * and a-0 is the lsb. Since it is a power of two, only one bit (a-x,
9710801Srene.dejong@arm.com     * with 0 <= x <= n) is set. If we subtract one from this number the bits
9810801Srene.dejong@arm.com     * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a
9910801Srene.dejong@arm.com     * bitwise AND with those two numbers results in an integer with all bits
10010801Srene.dejong@arm.com     * cleared.
10110801Srene.dejong@arm.com     */
10211321Ssteve.reinhardt@amd.com    if (numPlanes & planeMask)
10310801Srene.dejong@arm.com        fatal("Number of planes is not a power of 2 in flash device.\n");
10410801Srene.dejong@arm.com}
10510801Srene.dejong@arm.com
10610801Srene.dejong@arm.com/**
10710801Srene.dejong@arm.com * Initiates all the flash functions: initializes the lookup tables, age of
10810801Srene.dejong@arm.com * the device, etc. This can only be done once the disk image is known.
10910801Srene.dejong@arm.com * Thats why it can't be done in the constructor.
11010801Srene.dejong@arm.com */
11110801Srene.dejong@arm.comvoid
11210801Srene.dejong@arm.comFlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size)
11310801Srene.dejong@arm.com{
11410801Srene.dejong@arm.com    diskSize = disk_size * sector_size;
11510801Srene.dejong@arm.com    pagesPerBlock = blockSize / pageSize;
11610801Srene.dejong@arm.com    pagesPerDisk = diskSize / pageSize;
11710801Srene.dejong@arm.com    blocksPerDisk = diskSize / blockSize;
11810801Srene.dejong@arm.com
11910801Srene.dejong@arm.com    /** Sanity information: check flash configuration */
12010801Srene.dejong@arm.com    DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages "
12110801Srene.dejong@arm.com            "per disk\n", diskSize, pagesPerBlock, pagesPerDisk);
12210801Srene.dejong@arm.com
12310801Srene.dejong@arm.com    locationTable.resize(pagesPerDisk);
12410801Srene.dejong@arm.com
12510801Srene.dejong@arm.com    /**Garbage collection related*/
12610801Srene.dejong@arm.com    blockValidEntries.resize(blocksPerDisk, 0);
12710801Srene.dejong@arm.com    blockEmptyEntries.resize(blocksPerDisk, pagesPerBlock);
12810801Srene.dejong@arm.com
12910801Srene.dejong@arm.com    /**
13010801Srene.dejong@arm.com     * This is a bitmap. Every bit is a page
13110801Srene.dejong@arm.com     * unknownPages is a vector of 32 bit integers. If every page was an
13210801Srene.dejong@arm.com     * integer, the total size would be pagesPerDisk; since we can map one
13310801Srene.dejong@arm.com     * page per bit we need ceil(pagesPerDisk/32) entries. 32 = 1 << 5 hence
13410801Srene.dejong@arm.com     * it will do to just shift pagesPerDisk five positions and add one. This
13510801Srene.dejong@arm.com     * will allocate one integer to many for this data structure in the worst
13610801Srene.dejong@arm.com     * case.
13710801Srene.dejong@arm.com     */
13810801Srene.dejong@arm.com    unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF);
13910801Srene.dejong@arm.com
14010801Srene.dejong@arm.com    for (uint32_t count = 0; count < pagesPerDisk; count++) {
14110801Srene.dejong@arm.com        //setup lookup table + physical aspects
14210801Srene.dejong@arm.com
14310801Srene.dejong@arm.com        if (dataDistribution == Enums::stripe) {
14410801Srene.dejong@arm.com            locationTable[count].page = count / blocksPerDisk;
14510801Srene.dejong@arm.com            locationTable[count].block = count % blocksPerDisk;
14610801Srene.dejong@arm.com
14710801Srene.dejong@arm.com        } else {
14810801Srene.dejong@arm.com            locationTable[count].page = count % pagesPerBlock;
14910801Srene.dejong@arm.com            locationTable[count].block = count / pagesPerBlock;
15010801Srene.dejong@arm.com        }
15110801Srene.dejong@arm.com    }
15210801Srene.dejong@arm.com}
15310801Srene.dejong@arm.com
15410801Srene.dejong@arm.comFlashDevice::~FlashDevice()
15510801Srene.dejong@arm.com{
15610801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Remove FlashDevice\n");
15710801Srene.dejong@arm.com}
15810801Srene.dejong@arm.com
15910801Srene.dejong@arm.com/**
16010801Srene.dejong@arm.com * Handles the accesses to the device.
16110801Srene.dejong@arm.com * The function determines when certain actions are scheduled and schedules
16210801Srene.dejong@arm.com * an event that uses the callback function on completion of the action.
16310801Srene.dejong@arm.com */
16410801Srene.dejong@arm.comvoid
16510801Srene.dejong@arm.comFlashDevice::accessDevice(uint64_t address, uint32_t amount, Callback *event,
16610801Srene.dejong@arm.com                          Actions action)
16710801Srene.dejong@arm.com{
16810801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n"
16910801Srene.dejong@arm.com            , amount, pageSize);
17010801Srene.dejong@arm.com
17110801Srene.dejong@arm.com    std::vector<Tick> time(numPlanes, 0);
17210801Srene.dejong@arm.com    uint64_t logic_page_addr = address / pageSize;
17310801Srene.dejong@arm.com    uint32_t plane_address = 0;
17410801Srene.dejong@arm.com
17510801Srene.dejong@arm.com    /**
17610801Srene.dejong@arm.com     * The access will be broken up in a number of page accesses. The number
17710801Srene.dejong@arm.com     * of page accesses depends on the amount that needs to be transfered.
17810801Srene.dejong@arm.com     * The assumption here is that the interface is completely ignorant of
17910801Srene.dejong@arm.com     * the page size and that this model has to figure out all of the
18010801Srene.dejong@arm.com     * transaction characteristics.
18110801Srene.dejong@arm.com     */
18210801Srene.dejong@arm.com    for (uint32_t count = 0; amount > (count * pageSize); count++) {
18310801Srene.dejong@arm.com        uint32_t index = (locationTable[logic_page_addr].block *
18410801Srene.dejong@arm.com                          pagesPerBlock) + (logic_page_addr % pagesPerBlock);
18510801Srene.dejong@arm.com
18610801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d,"
18710801Srene.dejong@arm.com                " logic address 0x%8x\n", index,
18810801Srene.dejong@arm.com                locationTable[logic_page_addr].block, pagesPerBlock,
18910801Srene.dejong@arm.com                logic_page_addr);
19010801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count,
19110801Srene.dejong@arm.com                (count * pageSize));
19210801Srene.dejong@arm.com
19310801Srene.dejong@arm.com        plane_address = locationTable[logic_page_addr].block & planeMask;
19410801Srene.dejong@arm.com
19510801Srene.dejong@arm.com        if (action == ActionRead) {
19610801Srene.dejong@arm.com            //lookup
19710801Srene.dejong@arm.com            //call accessTimes
19810801Srene.dejong@arm.com            time[plane_address] += accessTimes(locationTable[logic_page_addr]
19910801Srene.dejong@arm.com                                               .block, ActionRead);
20010801Srene.dejong@arm.com
20110801Srene.dejong@arm.com            /*stats*/
20210801Srene.dejong@arm.com            stats.readAccess.sample(logic_page_addr);
20310801Srene.dejong@arm.com            stats.readLatency.sample(time[plane_address]);
20410801Srene.dejong@arm.com        } else { //write
20510801Srene.dejong@arm.com            //lookup
20610801Srene.dejong@arm.com            //call accessTimes if appropriate, page may be unknown, so lets
20710801Srene.dejong@arm.com            //give it the benefit of the doubt
20810801Srene.dejong@arm.com
20910801Srene.dejong@arm.com            if (getUnknownPages(index))
21010801Srene.dejong@arm.com                time[plane_address] += accessTimes
21110801Srene.dejong@arm.com                    (locationTable[logic_page_addr].block, ActionWrite);
21210801Srene.dejong@arm.com
21310801Srene.dejong@arm.com            else //A remap is needed
21410801Srene.dejong@arm.com                time[plane_address] += remap(logic_page_addr);
21510801Srene.dejong@arm.com
21610801Srene.dejong@arm.com            /*stats*/
21710801Srene.dejong@arm.com            stats.writeAccess.sample(logic_page_addr);
21810801Srene.dejong@arm.com            stats.writeLatency.sample(time[plane_address]);
21910801Srene.dejong@arm.com        }
22010801Srene.dejong@arm.com
22110801Srene.dejong@arm.com        /**
22210801Srene.dejong@arm.com         * Check if the page is known and used. unknownPages is a bitmap of
22310801Srene.dejong@arm.com         * all the pages. It tracks wether we can be sure that the
22410801Srene.dejong@arm.com         * information of this page is taken into acount in the model (is it
22510801Srene.dejong@arm.com         * considered in blockValidEntries and blockEmptyEntries?). If it has
22610801Srene.dejong@arm.com         * been used in the past, then it is known.
22710801Srene.dejong@arm.com         */
22810801Srene.dejong@arm.com        if (getUnknownPages(index)) {
22910801Srene.dejong@arm.com            clearUnknownPages(index);
23010801Srene.dejong@arm.com            --blockEmptyEntries[locationTable[logic_page_addr].block];
23110801Srene.dejong@arm.com            ++blockValidEntries[locationTable[logic_page_addr].block];
23210801Srene.dejong@arm.com        }
23310801Srene.dejong@arm.com
23410801Srene.dejong@arm.com        stats.fileSystemAccess.sample(address);
23510801Srene.dejong@arm.com        ++logic_page_addr;
23610801Srene.dejong@arm.com    }
23710801Srene.dejong@arm.com
23810801Srene.dejong@arm.com    /**
23910801Srene.dejong@arm.com     * previous part of the function found the times spend in different
24010801Srene.dejong@arm.com     * planes, now lets find the maximum to know when to callback the disk
24110801Srene.dejong@arm.com     */
24210801Srene.dejong@arm.com    for (uint32_t count = 0; count < numPlanes; count++){
24310801Srene.dejong@arm.com        plane_address = (time[plane_address] > time[count]) ? plane_address
24410801Srene.dejong@arm.com            : count;
24510801Srene.dejong@arm.com
24610801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count,
24710801Srene.dejong@arm.com                time[count]);
24810801Srene.dejong@arm.com
24911321Ssteve.reinhardt@amd.com        if (time[count] != 0) {
25010801Srene.dejong@arm.com
25110801Srene.dejong@arm.com            struct CallBackEntry cbe;
25210801Srene.dejong@arm.com            /**
25310801Srene.dejong@arm.com             * If there are no events for this plane, then add the current
25410801Srene.dejong@arm.com             * time to the occupation time; otherwise, plan it after the
25510801Srene.dejong@arm.com             * last event. If by chance that event is handled in this tick,
25610801Srene.dejong@arm.com             * then we would still end up with the same result.
25710801Srene.dejong@arm.com             */
25810801Srene.dejong@arm.com            if (planeEventQueue[count].empty())
25910801Srene.dejong@arm.com                cbe.time = time[count] + curTick();
26010801Srene.dejong@arm.com            else
26110801Srene.dejong@arm.com                cbe.time = time[count] +
26210801Srene.dejong@arm.com                           planeEventQueue[count].back().time;
26310801Srene.dejong@arm.com            cbe.function = NULL;
26410801Srene.dejong@arm.com            planeEventQueue[count].push_back(cbe);
26510801Srene.dejong@arm.com
26610801Srene.dejong@arm.com            DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time);
26710801Srene.dejong@arm.com
26810801Srene.dejong@arm.com            if (!planeEvent.scheduled())
26910801Srene.dejong@arm.com                schedule(planeEvent, planeEventQueue[count].back().time);
27010801Srene.dejong@arm.com            else if (planeEventQueue[count].back().time < planeEvent.when())
27110801Srene.dejong@arm.com                reschedule(planeEvent,
27210801Srene.dejong@arm.com                    planeEventQueue[plane_address].back().time, true);
27310801Srene.dejong@arm.com        }
27410801Srene.dejong@arm.com    }
27510801Srene.dejong@arm.com
27610801Srene.dejong@arm.com    //worst case two plane finish at the same time, each triggers an event
27710801Srene.dejong@arm.com    //and this callback will be called once. Maybe before the other plane
27810801Srene.dejong@arm.com    //could execute its event, but in the same tick.
27910801Srene.dejong@arm.com    planeEventQueue[plane_address].back().function = event;
28010801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n",
28110801Srene.dejong@arm.com            plane_address, planeEventQueue[plane_address].size());
28210801Srene.dejong@arm.com    DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
28310801Srene.dejong@arm.com}
28410801Srene.dejong@arm.com
28510801Srene.dejong@arm.com/**
28610801Srene.dejong@arm.com * When a plane completes its action, this event is triggered. When a
28710801Srene.dejong@arm.com * callback function was associated with that event, it will be called.
28810801Srene.dejong@arm.com */
28910801Srene.dejong@arm.com
29010801Srene.dejong@arm.comvoid
29110801Srene.dejong@arm.comFlashDevice::actionComplete()
29210801Srene.dejong@arm.com{
29310801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Plane action completed\n");
29410801Srene.dejong@arm.com    uint8_t plane_address = 0;
29510801Srene.dejong@arm.com
29610801Srene.dejong@arm.com    uint8_t next_event = 0;
29710801Srene.dejong@arm.com
29810801Srene.dejong@arm.com    /**Search for a callback that is supposed to happen in this Tick*/
29910801Srene.dejong@arm.com    for (plane_address = 0; plane_address < numPlanes; plane_address++) {
30010801Srene.dejong@arm.com        if (!planeEventQueue[plane_address].empty()) {
30110801Srene.dejong@arm.com            /**
30210801Srene.dejong@arm.com             * Invariant: All queued events are scheduled in the present
30310801Srene.dejong@arm.com             *  or future.
30410801Srene.dejong@arm.com             */
30510801Srene.dejong@arm.com            assert(planeEventQueue[plane_address].front().time >= curTick());
30610801Srene.dejong@arm.com
30710801Srene.dejong@arm.com            if (planeEventQueue[plane_address].front().time == curTick()) {
30810801Srene.dejong@arm.com                /**
30910801Srene.dejong@arm.com                 * To ensure that the follow-up action is executed correctly,
31010801Srene.dejong@arm.com                 * the callback entry first need to be cleared before it can
31110801Srene.dejong@arm.com                 * be called.
31210801Srene.dejong@arm.com                 */
31310801Srene.dejong@arm.com                Callback *temp = planeEventQueue[plane_address].front().
31410801Srene.dejong@arm.com                                 function;
31510801Srene.dejong@arm.com                planeEventQueue[plane_address].pop_front();
31610801Srene.dejong@arm.com
31710801Srene.dejong@arm.com                /**Found a callback, lets make it happen*/
31810801Srene.dejong@arm.com                if (temp != NULL) {
31910801Srene.dejong@arm.com                    DPRINTF(FlashDevice, "Callback, %d\n", plane_address);
32010801Srene.dejong@arm.com                    temp->process();
32110801Srene.dejong@arm.com                }
32210801Srene.dejong@arm.com            }
32310801Srene.dejong@arm.com        }
32410801Srene.dejong@arm.com    }
32510801Srene.dejong@arm.com
32610801Srene.dejong@arm.com    /** Find when to schedule the planeEvent next */
32710801Srene.dejong@arm.com    for (plane_address = 0; plane_address < numPlanes; plane_address++) {
32810801Srene.dejong@arm.com        if (!planeEventQueue[plane_address].empty())
32910801Srene.dejong@arm.com            if (planeEventQueue[next_event].empty() ||
33010801Srene.dejong@arm.com                    (planeEventQueue[plane_address].front().time <
33110801Srene.dejong@arm.com                     planeEventQueue[next_event].front().time))
33210801Srene.dejong@arm.com                next_event = plane_address;
33310801Srene.dejong@arm.com    }
33410801Srene.dejong@arm.com
33510801Srene.dejong@arm.com    /**Schedule the next plane that will be ready (if any)*/
33610801Srene.dejong@arm.com    if (!planeEventQueue[next_event].empty()) {
33710801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address);
33810801Srene.dejong@arm.com        reschedule(planeEvent, planeEventQueue[next_event].front().time, true);
33910801Srene.dejong@arm.com    }
34010801Srene.dejong@arm.com
34110801Srene.dejong@arm.com    checkDrain();
34210801Srene.dejong@arm.com
34310801Srene.dejong@arm.com    DPRINTF(FlashDevice, "returing from flash event\n");
34410801Srene.dejong@arm.com    DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
34510801Srene.dejong@arm.com}
34610801Srene.dejong@arm.com
34710801Srene.dejong@arm.com/**
34810801Srene.dejong@arm.com * Handles the remapping of the pages. It is a (I hope) sensible statistic
34910801Srene.dejong@arm.com * approach. asumption: garbage collection happens when a clean is needed
35010801Srene.dejong@arm.com * (may become stochastic function).
35110801Srene.dejong@arm.com */
35210801Srene.dejong@arm.comTick
35310801Srene.dejong@arm.comFlashDevice::remap(uint64_t logic_page_addr)
35410801Srene.dejong@arm.com{
35510801Srene.dejong@arm.com    /**
35610801Srene.dejong@arm.com     * Are there any empty left in this Block, or do we need to do an erase
35710801Srene.dejong@arm.com     */
35810801Srene.dejong@arm.com    if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) {
35910801Srene.dejong@arm.com        //just a remap
36010801Srene.dejong@arm.com        //update tables
36110801Srene.dejong@arm.com        --blockEmptyEntries[locationTable[logic_page_addr].block];
36210801Srene.dejong@arm.com        //access to this table won't be sequential anymore
36310801Srene.dejong@arm.com        locationTable[logic_page_addr].page = pagesPerBlock + 2;
36410801Srene.dejong@arm.com        //access new block
36510801Srene.dejong@arm.com        Tick time = accessTimes(locationTable[logic_page_addr].block,
36610801Srene.dejong@arm.com                                ActionWrite);
36710801Srene.dejong@arm.com
36810801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Remap returns %d ticks\n", time);
36910801Srene.dejong@arm.com        return time;
37010801Srene.dejong@arm.com
37110801Srene.dejong@arm.com    } else {
37210801Srene.dejong@arm.com        //calculate how much time GC would have taken
37310801Srene.dejong@arm.com        uint32_t block = locationTable[logic_page_addr].block;
37410801Srene.dejong@arm.com        Tick time = ((GCActivePercentage *
37510801Srene.dejong@arm.com                       (accessTimes(block, ActionCopy) +
37610801Srene.dejong@arm.com                        accessTimes(block, ActionErase)))
37710801Srene.dejong@arm.com                     / 100);
37810801Srene.dejong@arm.com
37910801Srene.dejong@arm.com        //use block as the logical start address of the block
38010801Srene.dejong@arm.com        block = locationTable[logic_page_addr].block * pagesPerBlock;
38110801Srene.dejong@arm.com
38210801Srene.dejong@arm.com        //assumption: clean will improve locality
38311180Ssascha.bischoff@ARM.com        for (uint32_t count = 0; count < pagesPerBlock; count++) {
38411180Ssascha.bischoff@ARM.com            assert(block + count < pagesPerDisk);
38510801Srene.dejong@arm.com            locationTable[block + count].page = (block + count) %
38610801Srene.dejong@arm.com                pagesPerBlock;
38710801Srene.dejong@arm.com        }
38810801Srene.dejong@arm.com
38910801Srene.dejong@arm.com        blockEmptyEntries[locationTable[logic_page_addr].block] =
39010801Srene.dejong@arm.com            pagesPerBlock;
39110801Srene.dejong@arm.com        /*stats*/
39210801Srene.dejong@arm.com        ++stats.totalGCActivations;
39310801Srene.dejong@arm.com
39410801Srene.dejong@arm.com        DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n",
39510801Srene.dejong@arm.com                time);
39610801Srene.dejong@arm.com
39710801Srene.dejong@arm.com        return time;
39810801Srene.dejong@arm.com    }
39910801Srene.dejong@arm.com
40010801Srene.dejong@arm.com}
40110801Srene.dejong@arm.com
40210801Srene.dejong@arm.com/**
40310801Srene.dejong@arm.com * Calculates the accesstime per operation needed
40410801Srene.dejong@arm.com */
40510801Srene.dejong@arm.comTick
40610801Srene.dejong@arm.comFlashDevice::accessTimes(uint64_t block, Actions action)
40710801Srene.dejong@arm.com{
40810801Srene.dejong@arm.com    Tick time = 0;
40910801Srene.dejong@arm.com
41010801Srene.dejong@arm.com    switch(action) {
41110801Srene.dejong@arm.com      case ActionRead: {
41210801Srene.dejong@arm.com          /**Just read the page*/
41310801Srene.dejong@arm.com          time = readLatency;
41410801Srene.dejong@arm.com      } break;
41510801Srene.dejong@arm.com
41610801Srene.dejong@arm.com      case ActionWrite: {
41710801Srene.dejong@arm.com          /**Write the page, and read the result*/
41810801Srene.dejong@arm.com          time = writeLatency + readLatency;
41910801Srene.dejong@arm.com      } break;
42010801Srene.dejong@arm.com
42110801Srene.dejong@arm.com      case ActionErase: {
42210801Srene.dejong@arm.com          /**Erase and check wether it was successfull*/
42310801Srene.dejong@arm.com          time = eraseLatency + readLatency;
42410801Srene.dejong@arm.com      } break;
42510801Srene.dejong@arm.com
42610801Srene.dejong@arm.com      case ActionCopy: {
42710801Srene.dejong@arm.com          /**Copy every valid page*/
42810801Srene.dejong@arm.com          uint32_t validpages = blockValidEntries[block];
42910801Srene.dejong@arm.com          time = validpages * (readLatency + writeLatency);
43010801Srene.dejong@arm.com      } break;
43110801Srene.dejong@arm.com
43210801Srene.dejong@arm.com      default: break;
43310801Srene.dejong@arm.com    }
43410801Srene.dejong@arm.com
43510801Srene.dejong@arm.com    //Used to determine sequential action.
43610801Srene.dejong@arm.com    DPRINTF(FlashDevice, "Access returns %d ticks\n", time);
43710801Srene.dejong@arm.com    return time;
43810801Srene.dejong@arm.com}
43910801Srene.dejong@arm.com
44010801Srene.dejong@arm.com/**
44110801Srene.dejong@arm.com * clearUnknownPages. defines that a page is known and used
44210801Srene.dejong@arm.com * unknownPages is a bitmap of all the pages. It tracks wether we can be sure
44310801Srene.dejong@arm.com * that the information of this page is taken into acount in the model (is it
44410801Srene.dejong@arm.com * considered in blockValidEntries and blockEmptyEntries?). If it has been
44510801Srene.dejong@arm.com * used in the past, then it is known. But it needs to be tracked to make
44610801Srene.dejong@arm.com * decisions about write accesses, and indirectly about copy actions. one
44710801Srene.dejong@arm.com * unknownPage entry is a 32 bit integer. So if we have a page index, then
44810801Srene.dejong@arm.com * that means that we need entry floor(index/32) (index >> 5) and we need to
44910801Srene.dejong@arm.com * select the bit which number is equal to the remainder of index/32
45010801Srene.dejong@arm.com * (index%32). The bit is cleared to make sure that we see it as considered
45110801Srene.dejong@arm.com * in the future.
45210801Srene.dejong@arm.com */
45310801Srene.dejong@arm.com
45410801Srene.dejong@arm.cominline
45510801Srene.dejong@arm.comvoid
45610801Srene.dejong@arm.comFlashDevice::clearUnknownPages(uint32_t index)
45710801Srene.dejong@arm.com{
45810801Srene.dejong@arm.com    unknownPages[index >> 5] &= ~(0x01 << (index % 32));
45910801Srene.dejong@arm.com}
46010801Srene.dejong@arm.com
46110801Srene.dejong@arm.com/**
46210801Srene.dejong@arm.com * getUnknownPages. Verify wether a page is known
46310801Srene.dejong@arm.com */
46410801Srene.dejong@arm.com
46510801Srene.dejong@arm.cominline
46610801Srene.dejong@arm.combool
46710801Srene.dejong@arm.comFlashDevice::getUnknownPages(uint32_t index)
46810801Srene.dejong@arm.com{
46910801Srene.dejong@arm.com    return unknownPages[index >> 5] & (0x01 << (index % 32));
47010801Srene.dejong@arm.com}
47110801Srene.dejong@arm.com
47210801Srene.dejong@arm.comvoid
47310801Srene.dejong@arm.comFlashDevice::regStats()
47410801Srene.dejong@arm.com{
47511523Sdavid.guillen@arm.com    AbstractNVM::regStats();
47611523Sdavid.guillen@arm.com
47710801Srene.dejong@arm.com    using namespace Stats;
47810801Srene.dejong@arm.com
47910801Srene.dejong@arm.com    std::string fd_name = name() + ".FlashDevice";
48010801Srene.dejong@arm.com
48110801Srene.dejong@arm.com    // Register the stats
48210801Srene.dejong@arm.com    /** Amount of GC activations*/
48310801Srene.dejong@arm.com    stats.totalGCActivations
48410801Srene.dejong@arm.com        .name(fd_name + ".totalGCActivations")
48510801Srene.dejong@arm.com        .desc("Number of Garbage collector activations")
48610801Srene.dejong@arm.com        .flags(none);
48710801Srene.dejong@arm.com
48810801Srene.dejong@arm.com    /** Histogram of address accesses*/
48910801Srene.dejong@arm.com    stats.writeAccess
49010801Srene.dejong@arm.com        .init(2)
49110801Srene.dejong@arm.com        .name(fd_name + ".writeAccessHist")
49210801Srene.dejong@arm.com        .desc("Histogram of write addresses")
49310801Srene.dejong@arm.com        .flags(pdf);
49410801Srene.dejong@arm.com    stats.readAccess
49510801Srene.dejong@arm.com        .init(2)
49610801Srene.dejong@arm.com        .name(fd_name + ".readAccessHist")
49710801Srene.dejong@arm.com        .desc("Histogram of read addresses")
49810801Srene.dejong@arm.com        .flags(pdf);
49910801Srene.dejong@arm.com    stats.fileSystemAccess
50010801Srene.dejong@arm.com        .init(100)
50110801Srene.dejong@arm.com        .name(fd_name + ".fileSystemAccessHist")
50210801Srene.dejong@arm.com        .desc("Histogram of file system accesses")
50310801Srene.dejong@arm.com        .flags(pdf);
50410801Srene.dejong@arm.com
50510801Srene.dejong@arm.com    /** Histogram of access latencies*/
50610801Srene.dejong@arm.com    stats.writeLatency
50710801Srene.dejong@arm.com        .init(100)
50810801Srene.dejong@arm.com        .name(fd_name + ".writeLatencyHist")
50910801Srene.dejong@arm.com        .desc("Histogram of write latency")
51010801Srene.dejong@arm.com        .flags(pdf);
51110801Srene.dejong@arm.com    stats.readLatency
51210801Srene.dejong@arm.com        .init(100)
51310801Srene.dejong@arm.com        .name(fd_name + ".readLatencyHist")
51410801Srene.dejong@arm.com        .desc("Histogram of read latency")
51510801Srene.dejong@arm.com        .flags(pdf);
51610801Srene.dejong@arm.com}
51710801Srene.dejong@arm.com
51810801Srene.dejong@arm.com/**
51910801Srene.dejong@arm.com * Serialize; needed to create checkpoints
52010801Srene.dejong@arm.com */
52110801Srene.dejong@arm.com
52210801Srene.dejong@arm.comvoid
52310905Sandreas.sandberg@arm.comFlashDevice::serialize(CheckpointOut &cp) const
52410801Srene.dejong@arm.com{
52510801Srene.dejong@arm.com    SERIALIZE_SCALAR(planeMask);
52610801Srene.dejong@arm.com
52711226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(unknownPages);
52811226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(blockValidEntries);
52911226SGeoffrey.Blake@arm.com    SERIALIZE_CONTAINER(blockEmptyEntries);
53010801Srene.dejong@arm.com
53110801Srene.dejong@arm.com    int location_table_size = locationTable.size();
53210801Srene.dejong@arm.com    SERIALIZE_SCALAR(location_table_size);
53310801Srene.dejong@arm.com    for (uint32_t count = 0; count < location_table_size; count++) {
53411226SGeoffrey.Blake@arm.com        paramOut(cp, csprintf("locationTable[%d].page", count),
53511226SGeoffrey.Blake@arm.com                 locationTable[count].page);
53611226SGeoffrey.Blake@arm.com        paramOut(cp, csprintf("locationTable[%d].block", count),
53711226SGeoffrey.Blake@arm.com                 locationTable[count].block);
53811226SGeoffrey.Blake@arm.com    }
53910801Srene.dejong@arm.com};
54010801Srene.dejong@arm.com
54110801Srene.dejong@arm.com/**
54210801Srene.dejong@arm.com * Unserialize; needed to restore from checkpoints
54310801Srene.dejong@arm.com */
54410801Srene.dejong@arm.com
54510801Srene.dejong@arm.comvoid
54610905Sandreas.sandberg@arm.comFlashDevice::unserialize(CheckpointIn &cp)
54710801Srene.dejong@arm.com{
54810801Srene.dejong@arm.com    UNSERIALIZE_SCALAR(planeMask);
54910801Srene.dejong@arm.com
55011226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(unknownPages);
55111226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(blockValidEntries);
55211226SGeoffrey.Blake@arm.com    UNSERIALIZE_CONTAINER(blockEmptyEntries);
55310801Srene.dejong@arm.com
55410801Srene.dejong@arm.com    int location_table_size;
55510801Srene.dejong@arm.com    UNSERIALIZE_SCALAR(location_table_size);
55610801Srene.dejong@arm.com    locationTable.resize(location_table_size);
55710801Srene.dejong@arm.com    for (uint32_t count = 0; count < location_table_size; count++) {
55811226SGeoffrey.Blake@arm.com        paramIn(cp, csprintf("locationTable[%d].page", count),
55911226SGeoffrey.Blake@arm.com                locationTable[count].page);
56011226SGeoffrey.Blake@arm.com        paramIn(cp, csprintf("locationTable[%d].block", count),
56111226SGeoffrey.Blake@arm.com                locationTable[count].block);
56211226SGeoffrey.Blake@arm.com    }
56310801Srene.dejong@arm.com};
56410801Srene.dejong@arm.com
56510801Srene.dejong@arm.com/**
56610801Srene.dejong@arm.com * Drain; needed to enable checkpoints
56710801Srene.dejong@arm.com */
56810801Srene.dejong@arm.com
56910913Sandreas.sandberg@arm.comDrainState
57010913Sandreas.sandberg@arm.comFlashDevice::drain()
57110801Srene.dejong@arm.com{
57210801Srene.dejong@arm.com    if (planeEvent.scheduled()) {
57310913Sandreas.sandberg@arm.com        DPRINTF(Drain, "Flash device is draining...\n");
57410913Sandreas.sandberg@arm.com        return DrainState::Draining;
57510801Srene.dejong@arm.com    } else {
57610801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device in drained state\n");
57710913Sandreas.sandberg@arm.com        return DrainState::Drained;
57810801Srene.dejong@arm.com    }
57910801Srene.dejong@arm.com}
58010801Srene.dejong@arm.com
58110801Srene.dejong@arm.com/**
58210801Srene.dejong@arm.com * Checkdrain; needed to enable checkpoints
58310801Srene.dejong@arm.com */
58410801Srene.dejong@arm.com
58510801Srene.dejong@arm.comvoid
58610801Srene.dejong@arm.comFlashDevice::checkDrain()
58710801Srene.dejong@arm.com{
58811179Ssascha.bischoff@ARM.com    if (drainState() != DrainState::Draining)
58910801Srene.dejong@arm.com        return;
59010801Srene.dejong@arm.com
59110801Srene.dejong@arm.com    if (planeEvent.when() > curTick()) {
59210801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device is still draining\n");
59310801Srene.dejong@arm.com    } else {
59410801Srene.dejong@arm.com        DPRINTF(Drain, "Flash device is done draining\n");
59510913Sandreas.sandberg@arm.com        signalDrainDone();
59610801Srene.dejong@arm.com    }
59710801Srene.dejong@arm.com}
598