OpenSSD Cosmos+ Platform Firmware  0.0.2
The firmware of Cosmos+ OpenSSD Platform for TOSHIBA nand flash module.
garbage_collection.c
Go to the documentation of this file.
1
2// garbage_collection.c for Cosmos+ OpenSSD
3// Copyright (c) 2017 Hanyang University ENC Lab.
4// Contributed by Yong Ho Song <yhsong@enc.hanyang.ac.kr>
5// Jaewook Kwak <jwkwak@enc.hanyang.ac.kr>
6//
7// This file is part of Cosmos+ OpenSSD.
8//
9// Cosmos+ OpenSSD is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; either version 3, or (at your option)
12// any later version.
13//
14// Cosmos+ OpenSSD is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17// See the GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with Cosmos+ OpenSSD; see the file COPYING.
21// If not, see <http://www.gnu.org/licenses/>.
23
25// Company: ENC Lab. <http://enc.hanyang.ac.kr>
26// Engineer: Jaewook Kwak <jwkwak@enc.hanyang.ac.kr>
27//
28// Project Name: Cosmos+ OpenSSD
29// Design Name: Cosmos+ Firmware
30// Module Name: Garbage Collector
31// File Name: garbage_collection.c
32//
33// Version: v1.0.0
34//
35// Description:
36// - select a victim block
37// - collect valid pages to a free block
38// - erase a victim block to make a free block
40
42// Revision History:
43//
44// * v1.0.0
45// - First draft
47
48#include "xil_printf.h"
49#include <assert.h>
50#include "memory_map.h"
51
53
55{
56 int dieNo, invalidSliceCnt;
57
59
60 for (dieNo = 0; dieNo < USER_DIES; dieNo++)
61 {
62 for (invalidSliceCnt = 0; invalidSliceCnt < SLICES_PER_BLOCK + 1; invalidSliceCnt++)
63 {
64 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock = BLOCK_NONE;
65 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = BLOCK_NONE;
66 }
67 }
68}
69
70void GarbageCollection(unsigned int dieNo)
71{
72 unsigned int victimBlockNo, pageNo, virtualSliceAddr, logicalSliceAddr, dieNoForGcCopy, reqSlotTag;
73
74 victimBlockNo = GetFromGcVictimList(dieNo);
75 dieNoForGcCopy = dieNo;
76
77 if (virtualBlockMapPtr->block[dieNo][victimBlockNo].invalidSliceCnt != SLICES_PER_BLOCK)
78 {
79 for (pageNo = 0; pageNo < USER_PAGES_PER_BLOCK; pageNo++)
80 {
81 virtualSliceAddr = Vorg2VsaTranslation(dieNo, victimBlockNo, pageNo);
82 logicalSliceAddr = virtualSliceMapPtr->virtualSlice[virtualSliceAddr].logicalSliceAddr;
83
84 if (logicalSliceAddr != LSA_NONE)
85 if (logicalSliceMapPtr->logicalSlice[logicalSliceAddr].virtualSliceAddr ==
86 virtualSliceAddr) // valid data
87 {
88 // read
89 reqSlotTag = GetFromFreeReqQ();
90
93 reqPoolPtr->reqPool[reqSlotTag].logicalSliceAddr = logicalSliceAddr;
103 reqSlotTag);
104 reqPoolPtr->reqPool[reqSlotTag].nandInfo.virtualSliceAddr = virtualSliceAddr;
105
106 SelectLowLevelReqQ(reqSlotTag);
107
108 // write
109 reqSlotTag = GetFromFreeReqQ();
110
113 reqPoolPtr->reqPool[reqSlotTag].logicalSliceAddr = logicalSliceAddr;
123 reqSlotTag);
125 FindFreeVirtualSliceForGc(dieNoForGcCopy, victimBlockNo);
126
130 .logicalSliceAddr = logicalSliceAddr;
131
132 SelectLowLevelReqQ(reqSlotTag);
133 }
134 }
135 }
136
137 EraseBlock(dieNo, victimBlockNo);
138}
139
140void PutToGcVictimList(unsigned int dieNo, unsigned int blockNo, unsigned int invalidSliceCnt)
141{
142 if (gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock != BLOCK_NONE)
143 {
144 virtualBlockMapPtr->block[dieNo][blockNo].prevBlock =
145 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock;
146 virtualBlockMapPtr->block[dieNo][blockNo].nextBlock = BLOCK_NONE;
147 virtualBlockMapPtr->block[dieNo][gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock]
148 .nextBlock = blockNo;
149 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = blockNo;
150 }
151 else
152 {
153 virtualBlockMapPtr->block[dieNo][blockNo].prevBlock = BLOCK_NONE;
154 virtualBlockMapPtr->block[dieNo][blockNo].nextBlock = BLOCK_NONE;
155 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock = blockNo;
156 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = blockNo;
157 }
158}
159
160unsigned int GetFromGcVictimList(unsigned int dieNo)
161{
162 unsigned int evictedBlockNo;
163 int invalidSliceCnt;
164
165 for (invalidSliceCnt = SLICES_PER_BLOCK; invalidSliceCnt > 0; invalidSliceCnt--)
166 {
167 if (gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock != BLOCK_NONE)
168 {
169 evictedBlockNo = gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock;
170
171 if (virtualBlockMapPtr->block[dieNo][evictedBlockNo].nextBlock != BLOCK_NONE)
172 {
173 virtualBlockMapPtr->block[dieNo][virtualBlockMapPtr->block[dieNo][evictedBlockNo].nextBlock]
175 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock =
176 virtualBlockMapPtr->block[dieNo][evictedBlockNo].nextBlock;
177 }
178 else
179 {
180 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock = BLOCK_NONE;
181 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = BLOCK_NONE;
182 }
183 return evictedBlockNo;
184 }
185 }
186
187 assert(!"[WARNING] There are no free blocks. Abort terminate this ssd. [WARNING]");
188 return BLOCK_FAIL;
189}
190
191void SelectiveGetFromGcVictimList(unsigned int dieNo, unsigned int blockNo)
192{
193 unsigned int nextBlock, prevBlock, invalidSliceCnt;
194
195 nextBlock = virtualBlockMapPtr->block[dieNo][blockNo].nextBlock;
196 prevBlock = virtualBlockMapPtr->block[dieNo][blockNo].prevBlock;
197 invalidSliceCnt = virtualBlockMapPtr->block[dieNo][blockNo].invalidSliceCnt;
198
199 if ((nextBlock != BLOCK_NONE) && (prevBlock != BLOCK_NONE))
200 {
201 virtualBlockMapPtr->block[dieNo][prevBlock].nextBlock = nextBlock;
202 virtualBlockMapPtr->block[dieNo][nextBlock].prevBlock = prevBlock;
203 }
204 else if ((nextBlock == BLOCK_NONE) && (prevBlock != BLOCK_NONE))
205 {
206 virtualBlockMapPtr->block[dieNo][prevBlock].nextBlock = BLOCK_NONE;
207 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = prevBlock;
208 }
209 else if ((nextBlock != BLOCK_NONE) && (prevBlock == BLOCK_NONE))
210 {
211 virtualBlockMapPtr->block[dieNo][nextBlock].prevBlock = BLOCK_NONE;
212 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock = nextBlock;
213 }
214 else
215 {
216 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].headBlock = BLOCK_NONE;
217 gcVictimMapPtr->gcVictimList[dieNo][invalidSliceCnt].tailBlock = BLOCK_NONE;
218 }
219}
P_LOGICAL_SLICE_MAP logicalSliceMapPtr
void EraseBlock(unsigned int dieNo, unsigned int blockNo)
Erase the specified block of the specified die and discard its LSAs.
unsigned int FindFreeVirtualSliceForGc(unsigned int copyTargetDieNo, unsigned int victimBlockNo)
P_VIRTUAL_SLICE_MAP virtualSliceMapPtr
P_VIRTUAL_BLOCK_MAP virtualBlockMapPtr
#define Vorg2VsaTranslation(dieNo, blockNo, pageNo)
Translate virtual NAND organization (location vector) into VSA.
#define LSA_NONE
#define BLOCK_NONE
#define BLOCK_FAIL
void UpdateTempDataBufEntryInfoBlockingReq(unsigned int bufEntry, unsigned int reqSlotTag)
Append the request to the blocking queue specified by given temp buffer entry.
Definition: data_buffer.c:298
unsigned int AllocateTempDataBuf(unsigned int dieNo)
Retrieve the index of temp buffer entry of the target die.
Definition: data_buffer.c:288
#define SLICES_PER_BLOCK
Definition: ftl_config.h:227
#define USER_DIES
Definition: ftl_config.h:219
#define USER_PAGES_PER_BLOCK
Definition: ftl_config.h:221
void InitGcVictimMap()
unsigned int GetFromGcVictimList(unsigned int dieNo)
void PutToGcVictimList(unsigned int dieNo, unsigned int blockNo, unsigned int invalidSliceCnt)
void GarbageCollection(unsigned int dieNo)
void SelectiveGetFromGcVictimList(unsigned int dieNo, unsigned int blockNo)
P_GC_VICTIM_MAP gcVictimMapPtr
struct _GC_VICTIM_MAP * P_GC_VICTIM_MAP
#define GC_VICTIM_MAP_ADDR
Definition: memory_map.h:106
unsigned int GetFromFreeReqQ()
Get a free request from the free request queue.
P_REQ_POOL reqPoolPtr
#define REQ_OPT_BLOCK_SPACE_MAIN
for the 1 bit flag REQ_OPTION::blockSpace.
#define REQ_OPT_DATA_BUF_TEMP_ENTRY
#define REQ_OPT_NAND_ECC_WARNING_OFF
#define REQ_CODE_WRITE
#define REQ_OPT_ROW_ADDR_DEPENDENCY_CHECK
#define REQ_OPT_NAND_ADDR_VSA
#define REQ_CODE_READ
#define REQ_TYPE_NAND
#define REQ_OPT_NAND_ECC_ON
void SelectLowLevelReqQ(unsigned int reqSlotTag)
Dispatch given NVMe/NAND request to corresponding request queue.
unsigned int entry
unsigned int tailBlock
unsigned int headBlock
GC_VICTIM_LIST_ENTRY gcVictimList[USER_DIES][SLICES_PER_BLOCK+1]
unsigned int virtualSliceAddr
LOGICAL_SLICE_ENTRY logicalSlice[SLICES_PER_SSD]
unsigned int virtualSliceAddr
unsigned int nandEccWarning
unsigned int dataBufFormat
Type of address stored in the SSD_REQ_FORMAT::dataBufInfo.
unsigned int nandAddr
Type of address stored in the SSD_REQ_FORMAT::nandInfo.
unsigned int blockSpace
unsigned int rowAddrDependencyCheck
unsigned int nandEcc
SSD_REQ_FORMAT reqPool[AVAILABLE_OUNTSTANDING_REQ_COUNT]
REQ_OPTION reqOpt
DATA_BUF_INFO dataBufInfo
unsigned int reqCode
unsigned int logicalSliceAddr
NAND_INFO nandInfo
unsigned int reqType
unsigned int prevBlock
unsigned int nextBlock
unsigned int invalidSliceCnt
VIRTUAL_BLOCK_ENTRY block[USER_DIES][USER_BLOCKS_PER_DIE]
unsigned int logicalSliceAddr
VIRTUAL_SLICE_ENTRY virtualSlice[SLICES_PER_SSD]