From 7a160a8629746ad233f92177cda3d7380eb49928 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 6 Dec 2020 17:44:45 +0100 Subject: [PATCH] mmc_disk: read using "simple DMA" The SDHCI spec also offers an "advanced DMA" mode where we can use scatter-gather lists. It would allow to remove several of the DMA restrictions, but hardware support for it is optional, so we need this version anyway. The geometry is retrieved on demand in the first read or write or in a call to the get geometry or get device size ioctl. It is not possible to retrieve it from the device initialization because that is called as part of the mmc_bus scanning, which needs a specific sequence of commands and keeps the bus locked to prevent drivers to insert their own commands in the middle of that sequence. TODO: - Move the DMA restrictions definition to sdhci_pci and forward it up to mmc_disk (which is the one creating the IOScheduler) - Decide if we want to keep non-DMA support (probably should, but it makes things more complex, because it uses virtual addresses) Change-Id: Ib1dd14eacf62052d747bfb3ef7820bc5a34d3030 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3471 Reviewed-by: Alex von Gluck IV --- headers/private/drivers/mmc.h | 10 +- .../kernel/bus_managers/mmc/mmc_bus.cpp | 4 +- src/add-ons/kernel/bus_managers/mmc/mmc_bus.h | 3 +- .../kernel/bus_managers/mmc/mmc_module.cpp | 17 +- src/add-ons/kernel/busses/mmc/Jamfile | 2 + src/add-ons/kernel/busses/mmc/sdhci_pci.cpp | 145 ++++++----- src/add-ons/kernel/busses/mmc/sdhci_pci.h | 6 +- .../kernel/drivers/disk/mmc/mmc_disk.cpp | 230 ++++++++++++++---- .../kernel/drivers/disk/mmc/mmc_disk.h | 17 +- 9 files changed, 306 insertions(+), 128 deletions(-) diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index aa34a01f4d..815d97488c 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -15,6 +15,9 @@ #define MMC_BUS_MODULE_NAME "bus_managers/mmc/driver_v1" +struct IOOperation; + + enum { CARD_TYPE_MMC, CARD_TYPE_SD, @@ -64,8 +67,7 @@ typedef struct mmc_bus_interface { status_t (*set_clock)(void* controller, uint32_t kilohertz); status_t (*execute_command)(void* controller, uint8_t command, uint32_t argument, uint32_t* result); - status_t (*read_naive)(void* controller, off_t pos, - void* buffer, size_t* _length); + status_t (*do_io)(void* controller, IOOperation* operation); } mmc_bus_interface; @@ -74,8 +76,8 @@ typedef struct mmc_device_interface { driver_module_info info; status_t (*execute_command)(device_node* node, uint8_t command, uint32_t argument, uint32_t* result); - status_t (*read_naive)(device_node* controller, uint16_t rca, off_t pos, - void* buffer, size_t* _length); + status_t (*do_io)(device_node* controller, uint16_t rca, + IOOperation* operation); } mmc_device_interface; diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp index de625f0e1e..096e8f5b4a 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp @@ -86,12 +86,12 @@ MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) status_t -MMCBus::Read(uint16_t rca, off_t position, void* buffer, size_t* length) +MMCBus::DoIO(uint16_t rca, IOOperation* operation) { status_t status = _ActivateDevice(rca); if (status != B_OK) return status; - return fController->read_naive(fCookie, position, buffer, length); + return fController->do_io(fCookie, operation); } diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h index 9692ef9489..bf39bdc93c 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h @@ -43,8 +43,7 @@ public: status_t ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response); - status_t Read(uint16_t rca, off_t position, void* buffer, - size_t* length); + status_t DoIO(uint16_t rca, IOOperation* operation); void AcquireBus() { acquire_sem(fLockSemaphore); } void ReleaseBus() { release_sem(fLockSemaphore); } diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp index c0ce6e5c36..6c713e83c3 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2018 Haiku, Inc. All rights reserved. + * Copyright 2018-2021 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * B Krishnan Iyer, krishnaniyer97@gmail.com + * Adrien Destugues, pulkomandy@pulkomandy.tk */ #include "mmc_bus.h" @@ -102,21 +103,23 @@ mmc_bus_execute_command(device_node* node, uint8_t command, uint32_t argument, static status_t -mmc_bus_read_naive(device_node* node, uint16_t rca, off_t pos, void* buffer, - size_t* _length) +mmc_bus_do_io(device_node* node, uint16_t rca, IOOperation* operation) { - // FIXME store the parent cookie in the bus cookie or something instead of - // getting/putting the parent each time. driver_module_info* mmc; void* cookie; + // FIXME store the parent cookie in the bus cookie or something instead of + // getting/putting the parent each time. device_node* parent = gDeviceManager->get_parent_node(node); gDeviceManager->get_driver(parent, &mmc, &cookie); gDeviceManager->put_node(parent); MMCBus* bus = (MMCBus*)cookie; bus->AcquireBus(); - status_t result = bus->Read(rca, pos, buffer, _length); + status_t result = B_OK; + + result = bus->DoIO(rca, operation); + bus->ReleaseBus(); return result; } @@ -172,7 +175,7 @@ mmc_device_interface mmc_bus_controller_module = { NULL }, mmc_bus_execute_command, - mmc_bus_read_naive + mmc_bus_do_io }; diff --git a/src/add-ons/kernel/busses/mmc/Jamfile b/src/add-ons/kernel/busses/mmc/Jamfile index 5b6f27ba7c..9b8fc1c754 100644 --- a/src/add-ons/kernel/busses/mmc/Jamfile +++ b/src/add-ons/kernel/busses/mmc/Jamfile @@ -2,7 +2,9 @@ SubDir HAIKU_TOP src add-ons kernel busses mmc ; SubDirC++Flags -fno-rtti ; +UsePrivateKernelHeaders ; UsePrivateHeaders drivers ; +SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; KernelAddon sdhci_pci : sdhci_pci.cpp diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index 3700c8c255..82bdfe616f 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -4,7 +4,9 @@ * * Authors: * B Krishnan Iyer, krishnaniyer97@gmail.com + * Adrien Destugues, pulkomandy@pulkomandy.tk */ +#include #include #include #include @@ -14,6 +16,7 @@ #include +#include "IOSchedulerSimple.h" #include "mmc.h" #include "sdhci_pci.h" @@ -49,7 +52,7 @@ class SdhciBus { status_t InitCheck(); void Reset(); void SetClock(int kilohertz); - status_t ReadNaive(off_t pos, void* buffer, size_t* _length); + status_t DoIO(IOOperation* operation); private: bool PowerOn(); @@ -114,8 +117,8 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq) return; } - EnableInterrupts(SDHCI_INT_CMD_CMP - | SDHCI_INT_BUF_READ_READY | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM); + EnableInterrupts(SDHCI_INT_CMD_CMP | SDHCI_INT_CARD_INS + | SDHCI_INT_CARD_REM | SDHCI_INT_TRANS_CMP); // We want to see the error bits in the status register, but not have an // interrupt trigger on them (we get a "command complete" interrupt on @@ -224,9 +227,10 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) fRegisters->argument = argument; fRegisters->command.SendCommand(command, replyType); - // Wait for command response to be available (either "command complete" or - // "buffer read ready" interrupt will happen, depending on the command) + // Wait for command response to be available ("command complete" interrupt) + TRACE("Wait for command complete..."); acquire_sem(fSemaphore); + TRACE("command complete OK\n"); if (fCommandResult & SDHCI_INT_ERROR) { fRegisters->interrupt_status |= fCommandResult; @@ -267,6 +271,12 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) break; } + if (replyType == Command::kR1bType) { + // R1b commands may use the data line so we must wait for the + // "transfer complete" interrupt here. + acquire_sem(fSemaphore); + } + ERROR("Command execution %d complete\n", command); return B_OK; } @@ -328,57 +338,75 @@ SdhciBus::SetClock(int kilohertz) status_t -SdhciBus::ReadNaive(off_t pos, void* buffer, size_t* _length) +SdhciBus::DoIO(IOOperation* operation) { - // TODO read multiple blocks at once (don't ignore _length) - fRegisters->block_size = 512; - fRegisters->block_count = 1; - fRegisters->transfer_mode = TransferMode::kSingle | TransferMode::kRead - | TransferMode::kAutoCmdDisabled | TransferMode::kNoDmaOrNoData; + bool isWrite = operation->IsWrite(); + if (isWrite) + return B_NOT_SUPPORTED; - uint32_t response; - status_t result; - result = ExecuteCommand(SD_READ_SINGLE_BLOCK, pos, &response); + static const uint32 kBlockSize = 512; + off_t offset = operation->Offset(); + generic_size_t length = operation->Length(); + + TRACE("%s %ld bytes at %ld\n", isWrite ? "Write" : "Read", length, offset); + + // Check that the IO scheduler did its job in following our DMA restrictions + // We can start a read only at a sector boundary + ASSERT(offset % kBlockSize == 0); + // We can only read complete sectors + ASSERT(length % kBlockSize == 0); + + const generic_io_vec* vecs = operation->Vecs(); + generic_size_t vecOffset = 0; + + // Must always be 512 (on SD cards it can be changed, but not on SDHC) + // FIXME can this be moved to the init function instead? + fRegisters->block_size = kBlockSize; + status_t result = B_OK; + + while (length > 0) { + size_t toCopy = std::min((generic_size_t)length, + vecs->length - vecOffset); + TRACE("Reading loop %ld bytes from position %ld\n", toCopy, offset); + + // If the current vec is empty, we can move to the next + if (toCopy == 0) { + vecs++; + vecOffset = 0; + continue; + } + + // With SDMA we can only transfer multiples of 1 sector + ASSERT(toCopy % kBlockSize == 0); + + fRegisters->system_address = vecs->base + vecOffset; + // fRegisters->adma_system_address = fDmaMemory; + + fRegisters->block_count = toCopy / kBlockSize; + + fRegisters->transfer_mode = TransferMode::kSingle | TransferMode::kRead + | TransferMode::kAutoCmd12Enable | TransferMode::kDmaEnable; + + uint32_t response; + result = ExecuteCommand(SD_READ_MULTIPLE_BLOCKS, offset, &response); + if (result != B_OK) + break; + + // Wait for DMA transfer to complete + // In theory we could go on and send other commands as long as they + // don't need the DAT lines, but it's overcomplicating things. + TRACE("Wait for transfer complete..."); + acquire_sem(fSemaphore); + TRACE("transfer complete OK.\n"); + + length -= toCopy; + vecOffset += toCopy; + offset += toCopy; + } if (result != B_OK) return result; - TRACE("Command response: %02x\n", response); - - if (fCommandResult & SDHCI_INT_BUF_READ_READY == 0) { - TRACE("No data!\n"); - return B_ERROR; - } - - // We don't know how to read more than 512 bytes (CMD18 would be needed) - if (*_length > 512) - *_length = 512; - - // read block data from Buffer Data Port register - // TODO use DMA instead - size_t to_read = *_length / sizeof(uint32_t); - size_t to_drop = 512 / sizeof(uint32_t) - to_read; - uint32_t* dest = (uint32_t*)buffer; - while(to_read > 0) { - *dest = fRegisters->buffer_data_port; - TRACE("read : 0x%x", *dest); - dest++; - to_read--; - } - - // We cannot read less than one sector, so we have to drop the extra data. - // This will be fixed when we use DMA and the IO scheduler (since it makes - // sure to only ask for complete sectors). - // Currently the IO scheduler does not support bounce buffers for non-DMA - // transfers. - while(to_drop > 0) { - (void*)fRegisters->buffer_data_port; - to_drop--; - } - - // wait for command complete interrupt - acquire_sem(fSemaphore); - return B_OK; } @@ -526,8 +554,6 @@ SdhciBus::RecoverError() int32 SdhciBus::HandleInterrupt() { - CALLED(); - #if 0 // We could use the slot register to quickly see for which slot the // interrupt is. But since we have an interrupt handler call for each slot @@ -578,12 +604,10 @@ SdhciBus::HandleInterrupt() TRACE("Command complete interrupt handled\n"); } - // handling data transfer interrupt - if (intmask & SDHCI_INT_BUF_READ_READY) { - TRACE("buffer read ready interrupt raised"); - fRegisters->interrupt_status |= (intmask & SDHCI_INT_BUF_READ_READY); - + if (intmask & SDHCI_INT_TRANS_CMP) { + fRegisters->interrupt_status |= SDHCI_INT_TRANS_CMP; release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE); + TRACE("Transfer complete interrupt handled\n"); } // handling bus power interrupt @@ -755,14 +779,13 @@ execute_command(void* controller, uint8_t command, uint32_t argument, } -//Very naive read protocol : non DMA, 32 bits at a time (size of Buffer Data Port) static status_t -read_naive(void* controller, off_t pos, void* buffer, size_t* _length) +do_io(void* controller, IOOperation* operation) { CALLED(); SdhciBus* bus = (SdhciBus*)controller; - return bus->ReadNaive(pos, buffer, _length); + return bus->DoIO(operation); } @@ -793,7 +816,7 @@ static mmc_bus_interface gSDHCIPCIDeviceModule = { set_clock, execute_command, - read_naive + do_io }; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.h b/src/add-ons/kernel/busses/mmc/sdhci_pci.h index 00dbc7a0fb..f1fa632159 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.h +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.h @@ -38,8 +38,8 @@ class TransferMode { static const uint8_t kAutoCmdDisabled = 0 << 2; static const uint8_t kAutoCmd12Enable = 1 << 2; static const uint8_t kAutoCmd23Enable = 2 << 2; - static const uint8_t kAutoCmdAutoSelect = - kAutoCmd23Enable | kAutoCmd12Enable; + static const uint8_t kAutoCmdAutoSelect + = kAutoCmd23Enable | kAutoCmd12Enable; // TODO block count enable @@ -65,7 +65,7 @@ class Command { static const uint8_t kSubCommand = 0x4; static const uint8_t kReplySizeMask = 0x3; static const uint8_t k32BitResponse = 0x2; - static const uint8_t k128BitResponse = 0x1; + static const uint8_t k128BitResponse = 0x1; static const uint8_t k32BitResponseCheckBusy = 0x3; // For simplicity pre-define the standard response types from the SD diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp index 486a84bd32..6a7b54836d 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp @@ -10,10 +10,10 @@ #include -#include +#include #include #include -#include +#include #include "mmc_disk.h" #include "mmc_icon.h" @@ -99,8 +99,57 @@ mmc_disk_register_device(device_node* node) { NULL } }; - return sDeviceManager->register_node(node - , MMC_DISK_DRIVER_MODULE_NAME, attrs, NULL, NULL); + return sDeviceManager->register_node(node, MMC_DISK_DRIVER_MODULE_NAME, + attrs, NULL, NULL); +} + + +static status_t +mmc_disk_execute_iorequest(void* data, IOOperation* operation) +{ + mmc_disk_driver_info* info = (mmc_disk_driver_info*)data; + status_t error; + + error = info->mmc->do_io(info->parent, info->rca, operation); + + if (error != B_OK) { + info->scheduler->OperationCompleted(operation, error, 0); + return error; + } + + info->scheduler->OperationCompleted(operation, B_OK, operation->Length()); + return B_OK; +} + + +static status_t +mmc_block_get_geometry(mmc_disk_driver_info* info, device_geometry* geometry) +{ + struct mmc_disk_csd csd; + TRACE("Get geometry\n"); + status_t error = info->mmc->execute_command(info->parent, SD_SEND_CSD, + info->rca << 16, (uint32_t*)&csd); + if (error != B_OK) { + TRACE("Could not get CSD! %s\n", strerror(error)); + return error; + } + + TRACE("CSD: %" PRIx64 " %" PRIx64 "\n", csd.bits[0], csd.bits[1]); + + if (csd.structure_version() < 3) { + geometry->bytes_per_sector = 1 << csd.read_bl_len(); + geometry->sectors_per_track = csd.c_size() + 1; + geometry->cylinder_count = 1 << (csd.c_size_mult() + 2); + geometry->head_count = 1; + geometry->device_type = B_DISK; + geometry->removable = true; // TODO detect eMMC which isn't + geometry->read_only = false; // TODO check write protect switch? + geometry->write_once = false; + return B_OK; + } + + TRACE("unknown CSD version %d\n", csd.structure_version()); + return B_NOT_SUPPORTED; } @@ -131,8 +180,48 @@ mmc_disk_init_driver(device_node* node, void** cookie) return B_BAD_DATA; } - TRACE("MMC card device initialized for RCA %x\n", info->rca); + static const uint32 kBlockSize = 512; // FIXME get it from the CSD + status_t error; + static const uint32 kDMAResourceBufferCount = 16; + static const uint32 kDMAResourceBounceBufferCount = 16; + + // TODO relax this when we have ADMA2 + // TODO the restrictions depend on the SDHCI bus and should be read + // from there, not hardcoded in mmc_disk + const dma_restrictions restrictions = { + 0, UINT32_MAX, /* Only 32bit address space in SDMA mode */ + 512, /* Align requests on sectors start and end */ + B_PAGE_SIZE, /* Do not cross pages (SDMA can't do it) */ + 512, 1, 512}; + + error = info->dmaResource.Init(restrictions, kBlockSize, + kDMAResourceBufferCount, kDMAResourceBounceBufferCount); + if (error != B_OK) { + TRACE("Failed to init DMA resource"); + free(info); + return error; + } + + info->scheduler = new(std::nothrow) IOSchedulerSimple(&info->dmaResource); + if (info->scheduler == NULL) { + TRACE("Failed to allocate scheduler"); + free(info); + return B_NO_MEMORY; + } + + error = info->scheduler->Init("mmc storage"); + if (error != B_OK) { + TRACE("Failed to init scheduler"); + delete info->scheduler; + free(info); + return error; + } + info->scheduler->SetCallback(&mmc_disk_execute_iorequest, info); + + memset(&info->geometry, 0, sizeof(info->geometry)); + + TRACE("MMC card device initialized for RCA %x\n", info->rca); *cookie = info; return B_OK; } @@ -143,6 +232,7 @@ mmc_disk_uninit_driver(void* _cookie) { CALLED(); mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie; + delete info->scheduler; sDeviceManager->put_node(info->parent); free(info); } @@ -216,7 +306,7 @@ mmc_block_open(void* _info, const char* path, int openMode, void** _cookie) static status_t mmc_block_close(void* cookie) { - mmc_disk_handle* handle = (mmc_disk_handle*)cookie; + //mmc_disk_handle* handle = (mmc_disk_handle*)cookie; CALLED(); return B_OK; @@ -234,24 +324,82 @@ mmc_block_free(void* cookie) } -static status_t +static status_t mmc_block_read(void* cookie, off_t pos, void* buffer, size_t* _length) { CALLED(); mmc_disk_handle* handle = (mmc_disk_handle*)cookie; - TRACE("Ready to execute %p\n", handle->info->mmc->read_naive); - return handle->info->mmc->read_naive(handle->info->parent, handle->info->rca, pos, buffer, _length); + + size_t length = *_length; + + if (handle->info->geometry.bytes_per_sector == 0) { + status_t error = mmc_block_get_geometry(handle->info, + &handle->info->geometry); + if (error != B_OK) { + TRACE("Failed to get disk capacity"); + return error; + } + } + + // Do not allow reading past device end + if (pos >= handle->info->DeviceSize()) + return B_BAD_VALUE; + if (pos + (off_t)length > handle->info->DeviceSize()) + length = handle->info->DeviceSize() - pos; + + IORequest request; + status_t status = request.Init(pos, (addr_t)buffer, length, false, 0); + if (status != B_OK) + return status; + + status = handle->info->scheduler->ScheduleRequest(&request); + if (status != B_OK) + return status; + + status = request.Wait(0, 0); + if (status == B_OK) + *_length = length; + return status; } static status_t mmc_block_write(void* cookie, off_t position, const void* buffer, - size_t* length) + size_t* _length) { CALLED(); mmc_disk_handle* handle = (mmc_disk_handle*)cookie; - return B_NOT_SUPPORTED; + size_t length = *_length; + + if (handle->info->geometry.bytes_per_sector == 0) { + status_t error = mmc_block_get_geometry(handle->info, + &handle->info->geometry); + if (error != B_OK) { + TRACE("Failed to get disk capacity"); + return error; + } + } + + if (position >= handle->info->DeviceSize()) + return B_BAD_VALUE; + if (position + (off_t)length > handle->info->DeviceSize()) + length = handle->info->DeviceSize() - position; + + IORequest request; + status_t status = request.Init(position, (addr_t)buffer, length, true, 0); + if (status != B_OK) + return status; + + status = handle->info->scheduler->ScheduleRequest(&request); + if (status != B_OK) + return status; + + status = request.Wait(0, 0); + if (status == B_OK) + *_length = length; + + return status; } @@ -261,34 +409,7 @@ mmc_block_io(void* cookie, io_request* request) CALLED(); mmc_disk_handle* handle = (mmc_disk_handle*)cookie; - return B_NOT_SUPPORTED; -} - - -static status_t -mmc_block_get_geometry(mmc_disk_handle* handle, device_geometry* geometry) -{ - struct mmc_disk_csd csd; - TRACE("Ready to execute %p\n", handle->info->mmc->execute_command); - handle->info->mmc->execute_command(handle->info->parent, SD_SEND_CSD, - handle->info->rca << 16, (uint32_t*)&csd); - - TRACE("CSD: %lx %lx\n", csd.bits[0], csd.bits[1]); - - if (csd.structure_version() == 0) { - geometry->bytes_per_sector = 1 << csd.read_bl_len(); - geometry->sectors_per_track = csd.c_size() + 1; - geometry->cylinder_count = 1 << (csd.c_size_mult() + 2); - geometry->head_count = 1; - geometry->device_type = B_DISK; - geometry->removable = true; // TODO detect eMMC which isn't - geometry->read_only = true; // TODO add write support - geometry->write_once = false; - return B_OK; - } - - TRACE("unknown CSD version %d\n", csd.structure_version()); - return B_NOT_SUPPORTED; + return handle->info->scheduler->ScheduleRequest(request); } @@ -316,9 +437,20 @@ mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length) case B_GET_DEVICE_SIZE: { - //size_t size = info->capacity * info->block_size; - //return user_memcpy(buffer, &size, sizeof(size_t)); - return B_NOT_SUPPORTED; + // Legacy ioctl, use B_GET_GEOMETRY + if (info->geometry.bytes_per_sector == 0) { + status_t error = mmc_block_get_geometry(info, &info->geometry); + if (error != B_OK) { + TRACE("Failed to get disk capacity"); + return error; + } + } + + uint64_t size = info->DeviceSize(); + if (size > SIZE_MAX) + return B_NOT_SUPPORTED; + size_t size32 = size; + return user_memcpy(buffer, &size32, sizeof(size_t)); } case B_GET_GEOMETRY: @@ -326,12 +458,16 @@ mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length) if (buffer == NULL || length < sizeof(device_geometry)) return B_BAD_VALUE; - device_geometry geometry; - status_t status = mmc_block_get_geometry(handle, &geometry); - if (status != B_OK) - return status; + if (info->geometry.bytes_per_sector == 0) { + status_t error = mmc_block_get_geometry(info, &info->geometry); + if (error != B_OK) { + TRACE("Failed to get disk capacity"); + return error; + } + } - return user_memcpy(buffer, &geometry, sizeof(device_geometry)); + return user_memcpy(buffer, &info->geometry, + sizeof(device_geometry)); } case B_GET_ICON_NAME: diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h index 1775b997ad..fc27a65db8 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h @@ -17,17 +17,30 @@ #include +#include "IOSchedulerSimple.h" + + +// This is the device info structure, allocated once per device typedef struct { device_node* node; device_node* parent; mmc_device_interface* mmc; uint16_t rca; - size_t block_size; - uint64_t capacity; + device_geometry geometry; + + DMAResource dmaResource; + IOScheduler* scheduler; + + off_t DeviceSize() const { + return (off_t)geometry.bytes_per_sector * geometry.sectors_per_track + * geometry.cylinder_count * geometry.head_count; + } } mmc_disk_driver_info; +// This is allocated once per open() call on the device (there can be multiple +// open file descriptors for the same device) typedef struct { mmc_disk_driver_info* info; } mmc_disk_handle;