mmc_disk: implement B_TRIM_DEVICE
Change-Id: Ib08a1e196441f35550fe221b912332b4803a04b4 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3641 Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
cef80a1fb7
commit
2028d6386c
@@ -49,6 +49,11 @@ enum SD_COMMANDS {
|
||||
SD_WRITE_SINGLE_BLOCK = 24,
|
||||
SD_WRITE_MULTIPLE_BLOCKS = 25,
|
||||
|
||||
// Erase commands, class 5
|
||||
SD_ERASE_WR_BLK_START = 32,
|
||||
SD_ERASE_WR_BLK_END = 33,
|
||||
SD_ERASE = 38,
|
||||
|
||||
// Application specific commands, class 8
|
||||
SD_APP_CMD = 55,
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#define _FS_TRIM_SUPPORT_H
|
||||
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <KernelExport.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <syscall_restart.h>
|
||||
|
||||
@@ -213,6 +213,7 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
||||
replyType = Command::kR6Type;
|
||||
break;
|
||||
case SD_SELECT_DESELECT_CARD:
|
||||
case SD_ERASE:
|
||||
replyType = Command::kR1bType;
|
||||
break;
|
||||
case SD_SEND_IF_COND:
|
||||
@@ -225,6 +226,8 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
||||
replyType = Command::kR1Type | Command::kDataPresent;
|
||||
break;
|
||||
case SD_APP_CMD:
|
||||
case SD_ERASE_WR_BLK_START:
|
||||
case SD_ERASE_WR_BLK_END:
|
||||
case SD_SET_BUS_WIDTH: // SD Application command
|
||||
replyType = Command::kR1Type;
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020 Haiku, Inc. All rights reserved.
|
||||
* Copyright 2018-2021 Haiku, Inc. All rights reserved.
|
||||
* Copyright 2020, Viveris Technologies.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
@@ -23,8 +23,10 @@
|
||||
#include <drivers/KernelExport.h>
|
||||
#include <drivers/Drivers.h>
|
||||
#include <kernel/OS.h>
|
||||
#include <util/fs_trim_support.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
// #include <fs/devfs.h>
|
||||
|
||||
#define TRACE_MMC_DISK
|
||||
#ifdef TRACE_MMC_DISK
|
||||
@@ -39,6 +41,9 @@
|
||||
#define MMC_DISK_DEVICE_MODULE_NAME "drivers/disk/mmc/mmc_disk/device_v1"
|
||||
#define MMC_DEVICE_ID_GENERATOR "mmc/device_id"
|
||||
|
||||
|
||||
static const uint32 kBlockSize = 512; // FIXME get it from the CSD
|
||||
|
||||
static device_manager_info* sDeviceManager;
|
||||
|
||||
|
||||
@@ -237,7 +242,6 @@ mmc_disk_init_driver(device_node* node, void** cookie)
|
||||
else
|
||||
info->flags = kIoCommandOffsetAsSectors;
|
||||
|
||||
static const uint32 kBlockSize = 512; // FIXME get it from the CSD
|
||||
status_t error;
|
||||
|
||||
static const uint32 kDMAResourceBufferCount = 16;
|
||||
@@ -475,6 +479,73 @@ mmc_block_io(void* cookie, io_request* request)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_block_trim(mmc_disk_driver_info* info, fs_trim_data* trimData)
|
||||
{
|
||||
enum {
|
||||
kEraseModeErase = 0, // force to actually erase the data
|
||||
kEraseModeDiscard = 1,
|
||||
// just mark the data as unused for internal wear leveling
|
||||
// algorithms
|
||||
kEraseModeFullErase = 2, // erase the whole card
|
||||
};
|
||||
TRACE("trim_device()\n");
|
||||
|
||||
uint64 trimmedSize = 0;
|
||||
status_t result = B_OK;
|
||||
for (uint32 i = 0; i < trimData->range_count; i++) {
|
||||
off_t offset = trimData->ranges[i].offset;
|
||||
off_t length = trimData->ranges[i].size;
|
||||
|
||||
// Round up offset and length to multiple of the sector size
|
||||
// The offset is rounded up, so some space may be left
|
||||
// (not trimmed) at the start of the range.
|
||||
offset = ROUNDUP(offset, kBlockSize);
|
||||
// Adjust the length for the possibly skipped range
|
||||
length -= trimData->ranges[i].offset - offset;
|
||||
// The length is rounded down, so some space at the end may also
|
||||
// be left (not trimmed).
|
||||
length &= ~(kBlockSize - 1);
|
||||
|
||||
if (length == 0) {
|
||||
trimmedSize += trimData->ranges[i].size;
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("trim %" B_PRIdOFF " bytes from %" B_PRIdOFF "\n",
|
||||
length, offset);
|
||||
|
||||
ASSERT(offset % kBlockSize == 0);
|
||||
ASSERT(length % kBlockSize == 0);
|
||||
|
||||
if (info->flags & kIoCommandOffsetAsSectors) {
|
||||
offset /= kBlockSize;
|
||||
length /= kBlockSize;
|
||||
}
|
||||
|
||||
uint32_t response;
|
||||
result = info->mmc->execute_command(info->parent, info->parentCookie,
|
||||
info->rca, SD_ERASE_WR_BLK_START, offset, &response);
|
||||
if (result != B_OK)
|
||||
break;
|
||||
result = info->mmc->execute_command(info->parent, info->parentCookie,
|
||||
info->rca, SD_ERASE_WR_BLK_END, offset + length, &response);
|
||||
if (result != B_OK)
|
||||
break;
|
||||
result = info->mmc->execute_command(info->parent, info->parentCookie,
|
||||
info->rca, SD_ERASE, kEraseModeDiscard, &response);
|
||||
if (result != B_OK)
|
||||
break;
|
||||
|
||||
trimmedSize += trimData->ranges[i].size;
|
||||
}
|
||||
|
||||
trimData->trimmed_size = trimmedSize;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
|
||||
{
|
||||
@@ -550,6 +621,13 @@ mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
|
||||
return user_memcpy(buffer, &iconData, sizeof(device_icon));
|
||||
}
|
||||
|
||||
case B_TRIM_DEVICE:
|
||||
{
|
||||
// We know the buffer is kernel-side because it has been
|
||||
// preprocessed in devfs
|
||||
return mmc_block_trim(info, (fs_trim_data*)buffer);
|
||||
}
|
||||
|
||||
/*case B_FLUSH_DRIVE_CACHE:
|
||||
return synchronize_cache(info);*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user