diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/medmmc.cpp --- a/kernel/eka/drivers/medmmc/medmmc.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/medmmc/medmmc.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1999-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -50,6 +50,7 @@ #define __ASSERT_CACHE(c,p) #endif +#include "medmmc.h" GLREF_C TInt GetMediaDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry, TUint16& aReservedSectors, const TMMCard* aCardP); GLREF_C TBool MBRMandatory(const TMMCard* aCardP); @@ -59,11 +60,10 @@ extern TInt GetCardFormatInfo(const TMMCard* aCardP, TLocalDriveCapsV5& aCaps); +IMPORT_C extern const TUint KTRIMEnabled; + const TInt KStackNumber = 0; -const TInt KDiskSectorSize=512; -const TInt KDiskSectorShift=9; - const TInt KIdleCurrentInMilliAmps = 1; const TInt KMBRFirstPartitionEntry=0x1BE; @@ -90,237 +90,6 @@ const TInt64 KInvalidBlock = -1; const TInt KNoCacheBlock = -1; -class DMmcMediaDriverFlash : public DMediaDriver - { -public: - DMmcMediaDriverFlash(TInt aMediaId); - ~DMmcMediaDriverFlash(); - // ...from DMediaDriver - virtual void Close(); - // replacing pure virtual - virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*); - virtual TInt Request(TLocDrvRequest& aRequest); - virtual TInt PartitionInfo(TPartitionInfo& anInfo); - virtual void NotifyPowerDown(); - virtual void NotifyEmergencyPowerDown(); - // For creation by DPhysicalDeviceMediaMmcFlash - TInt DoCreate(TInt aMediaId); - -private: - enum TPanic - { - EDRInUse = 0x0000, EDRStart, EDRNotPositive, EDREnd, - ELRRequest = 0x0010, ELRStart, ELRNotPositive, ELREnd, ELRCached, - EDWInUse = 0x0020, EDWStart, EDWNotPositive, EDWEnd, - EDFInUse = 0x0030, EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket, - ELWRequest = 0x0040, ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign, - ELWLength, ELFStart, ELFEnd, ELFNotPositive, - ERPIInUse = 0x0050, - EPCInUse = 0x0060, EPCFunc, - ESECBQueued = 0x0070, - EDSEDRequest = 0x0080, EDSEDNotErrComplete, - ECRReqIdle = 0x0090, ECRRequest, - ERRBStAlign = 0x00a0, ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos, - ERRBOverflow, ERRBCchInv, ERRBExist, - ERWBStPos = 0x00b0, ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv, - EMBStPos = 0x00c0, EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign, - EMBOverflow, EMBCchInvPre, EMBCchInvPost, - EBGAStPos = 0x00d0, EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign, - EBGAOverflow, EBGACchInv, - EICMNegative = 0x00e0, EICMOverflow, ECMIOverflow, - EGCBAlign = 0x00f0, EGCBPos, EGCBCchInv, - - ECFSessPtrNull = 0x0100, // Code Fault - session pointer NULL - - EDBNotEven = 0x0110, // Not and even number of blocks in the buffer cache - EDBCBQueued = 0x0111, // The data transfer callback is already queued - EDBLength = 0x0112, // The length of data to transfer in data transfer callback is not positive - EDBLengthTooBig = 0x0113, // The length of data to transfer in data transfer callback is too big - EDBOffsetTooBig = 0x0114, // The Offset into the user data buffer is too big - EDBCacheInvalid = 0x0115, // The cache is invalid at the end of data transfer - EDBNotOptimal = 0x0116, // Due to Cache size DB functionality will never be utilised - ENoDBSupport = 0x0120, // DMA request arrived but PSL does not support double buffering - ENotDMAAligned = 0x0121, - }; - static void Panic(TPanic aPnc); - - enum TMediaRequest - { - EMReqRead = 0, - EMReqWrite = 1, - EMReqFormat = 2, - EMReqPtnInfo, - EMReqPswdCtrl, - EMReqForceErase, - EMReqUpdatePtnInfo, - EMReqWritePasswordData, - EMReqIdle, - EMReqEMMCPtnInfo, - }; - enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd}; - - enum {KWtRBMFst = 0x00000001, // iWtRBM - Read First Block only - KWtRBMLst = 0x00000002, // iWtRBM - Read Last Block only - KWtMinFst = 0x00000004, // iWtRBM - Write First Block only - KWtMinLst = 0x00000008, // iWtRBM - Write Last Block only - KIPCSetup = 0x00000010, // iRdROB - IPC Setup Next Iteration - KIPCWrite = 0x00000020}; // iRdROB - IPC Write Next Iteration - -private: - // MMC device specific stuff - TInt DoRead(); - TInt DoWrite(); - TInt DoFormat(); - TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo); - - inline DMMCStack& Stack() const; - inline TInt CardNum() const; - inline TMediaRequest CurrentRequest() const; - - TInt LaunchRead(TInt64 aStart, TUint32 aLength); - TInt LaunchDBRead(); - TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength); - - TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq); - TInt LaunchFormat(TInt64 aStart, TUint32 aLength); - - TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData); - TInt LaunchRPIRead(); - TInt LaunchRPIErase(); - TInt DecodePartitionInfo(); - TInt WritePartitionInfo(); - TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry); - TInt CreateDefaultPartition(); - - -#if defined __TEST_PAGING_MEDIA_DRIVER__ - TInt HandleControlIORequest(); -#endif - - static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors); - - TInt CheckDevice(TMediaReqType aReqType); - - static void SessionEndCallBack(TAny* aMediaDriver); - static void SessionEndDfc(TAny* aMediaDriver); - void DoSessionEndDfc(); - - static void DataTransferCallBack(TAny* aMediaDriver); - static void DataTransferCallBackDfc(TAny* aMediaDriver); - - void DoReadDataTransferCallBack(); - void DoWriteDataTransferCallBack(); - void DoPhysReadDataTransferCallBack(); - void DoPhysWriteDataTransferCallBack(); - - TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength); - TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength); - void PrepareNextPhysicalFragment(); - - TInt EngageAndSetReadRequest(TMediaRequest aRequest); - TInt EngageAndSetWriteRequest(TMediaRequest aRequest); - TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent); - void CompleteRequest(TInt aReason); - - TInt ReadDataUntilCacheExhausted(TBool* aAllDone); - TInt WriteDataToUser(TUint8* aBufPtr); - TInt ReadDataFromUser(TDes8& aDes, TInt aOffset); - TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength); - TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM); - void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex); - void BuildGammaArray(TInt64 aStart, TInt64 aEnd); - void InvalidateCache(); - void InvalidateCache(TInt64 aStart, TInt64 aEnd); - TUint8* IdxToCchMem(TInt aIdx) const; - TInt CchMemToIdx(TUint8* aMemP) const; - - TInt DoPasswordOp(); - void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData); - void Reset(); - TInt AllocateSession(); - -#ifdef _DEBUG_CACHE - TBool CacheInvariant(); - TUint8* GetCachedBlock(TInt64 aAddr); -#endif -private: - DMMCStack* iStack; // controller objects - TMMCard* iCard; - DMMCSession* iSession; - DMMCSocket* iSocket; - - TInt iCardNumber; - - TUint iBlkLenLog2; // cached CSD data - TUint32 iBlkLen; - TInt64 iBlkMsk; - TBool iReadBlPartial; - TUint32 iPrWtGpLen; // preferred write group size in bytes, - TInt64 iPrWtGpMsk; - - TInt iReadCurrentInMilliAmps; // power management - TInt iWriteCurrentInMilliAmps; - - TUint8* iMinorBuf; // MBR, CMD42, partial read - TUint8* iCacheBuf; // cached buffer - TUint32 iMaxBufSize; - TInt iBlocksInBuffer; - TInt64* iCachedBlocks; - TInt* iGamma; // B lookup, ReserveReadBlocks() - TUint8* iIntBuf; // start of current buffer region - TInt iLstUsdCchEnt; // index of last used cache entry - - TLocDrvRequest* iCurrentReq; // Current Request - TMediaRequest iMedReq; - - TInt64 iReqStart; // user-requested start region - TInt64 iReqCur; // Currently requested start region - TInt64 iReqEnd; // user-requested end region - TInt64 iPhysStart; // physical region for one operation - TInt64 iPhysEnd; // physical end point for one operation - TInt64 iDbEnd; // Double buffer end point for one operation - - TUint64 iEraseUnitMsk; - - TUint iWtRBM; // Write - Read Before Modify Flags - TUint iRdROB; // Read - Read Odd Blocks Flags - - TInt iFragOfset; - TUint32 iIPCLen; - TUint32 iNxtIPCLen; - TUint32 iBufOfset; - - TUint iHiddenSectors; // bootup / password - - TMMCCallBack iSessionEndCallBack; - TDfc iSessionEndDfc; - - TPartitionInfo* iPartitionInfo; - TMMCMediaTypeEnum iMediaType; - TMMCEraseInfo iEraseInfo; - TBool iMbrMissing; - TInt iMediaId; - - DMMCStack::TDemandPagingInfo iDemandPagingInfo; - -#if defined(__TEST_PAGING_MEDIA_DRIVER__) - SMmcStats iMmcStats; -#endif // __TEST_PAGING_MEDIA_DRIVER__ - - TMMCCallBack iDataTransferCallBack; // Callback registered with the MMC stack to perform double-buffering - TDfc iDataTransferCallBackDfc; // ...and the associated DFC queue. - - TBool iSecondBuffer; // Specified the currently active buffer - TBool iDoLastRMW; // ETrue if the last double-buffer transfer requires RMW modification - TBool iDoDoubleBuffer; // ETrue if double-buffering is currently active - TBool iDoPhysicalAddress; // ETrue if Physical Addressing is currently active - TBool iCreateMbr; - TBool iReadToEndOfCard; // {Read Only} ETrue if Reading to end of Card - - TBool iInternalSlot; - - DEMMCPartitionInfo* iMmcPartitionInfo; // Responsible for decoding partitions for embedded devices - }; // ======== DPhysicalDeviceMediaMmcFlash ======== @@ -471,6 +240,10 @@ // NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId)); OstTraceExt2( TRACE_FLOW, DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH, "> DMmcMediaDriverFlash::DMmcMediaDriverFlash;aMediaId=%d;iMediaId=%d", (TInt) aMediaId, (TInt) iMediaId ); + for(TInt drv = 0; drv < KMaxLocalDrives; drv++) + { + SetEMmcPartitionMapping(drv, TExtendedCSD::ESelectUserArea); + } } @@ -540,12 +313,13 @@ iMinorBuf = buf; + // reserve KRpmbOneFramePacketLength bytes after the minor buffer for RPMB requests / responses // cache buffer can use rest of blocks in buffer. Does not have to be power of 2. - iCacheBuf = iMinorBuf + minorBufLen; + iCacheBuf = iMinorBuf + minorBufLen + KRpmbOneFramePacketLength; // We need to devide up the buffer space between the media drivers. // The number of buffer sub-areas = number of physical card slots * number of media - bufLen-= minorBufLen; + bufLen-= (minorBufLen + KRpmbOneFramePacketLength); DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia; TInt physicalCardSlots = iStack->iMaxCardsInStack; TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1; @@ -1160,7 +934,8 @@ } // Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd. - if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0) + if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0 || + (iCurrentReq->Id() == DLocalDrive::EDeleteNotify && (iPhysStart - iPhysEnd) % KMMCardHighCapBlockSize == 0 )) // handle TRIM case where erase is aligned to 512 blocks { // Aligned erase // Check that erase commands are supported prior to issuing an erase command @@ -1174,6 +949,10 @@ iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector) } + if(iCurrentReq->Id() == DLocalDrive::EDeleteNotify) + { + iSession->Command().iFlags|= KMMCCmdFlagDeleteNotify; //set flags for Trim + } } else { @@ -1200,7 +979,7 @@ memset (iCacheBuf, 0x00, writeLen); iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); } - + r = EngageAndSetWriteRequest(EMReqFormat); } OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_EXIT, this, r ); @@ -2307,6 +2086,10 @@ { iReqCur = iPhysEnd; } + else if(iCurrentReq->Id() == DLocalDrive::EDeleteNotify) //handle DeleteNotify case + { + iReqCur = iPhysEnd; + } else { // Formating to a mis-aligned boundary, so we can't make best use of @@ -2727,9 +2510,25 @@ iMedReq = aRequest; SetCurrentConsumption(aCurrent); +#ifdef EMMC_PARTITION_TEST_MODE_ENABLED + if((iSession->Partition() & TExtendedCSD::EPartitionTestMode) != 0) + { + // driver in test mode, target partition must be set by ControlIO() KMmcSwitchPartition + } + else +#endif // EMMC_PARTITION_TEST_MODE_ENABLED + if (iCurrentReq) + // if iCurrentReq is NULL then it is assuned to be a request for a removable drive + // multiple physical partitions are not supported on removable drives hence partition settting is not requied + { + TInt ptn = iCurrentReq->Drive()->iPartitionNumber; + TInt eMmcPtn = GetEMmcPartitionMapping(ptn); + iSession->SetPartition(eMmcPtn); + } + // Reset the card pointer just in case the stack has changed it. iSession->SetCard(iCard); - + TInt r = InCritical(); if (r == KErrNone) { @@ -2783,6 +2582,9 @@ aInfo.iConnectionBusType = EConnectionBusInternal; aInfo.iDriveAtt = KDriveAttLocal; aInfo.iMediaAtt = KMediaAttFormattable; + + if(iCard->ExtendedCSD().ExtendedCSDRev() >= 5 && KTRIMEnabled) //TRIM support for v4.4+ + aInfo.iMediaAtt |= KMediaAttDeleteNotify; if(iCard->iFlags & KMMCardIsLockable) aInfo.iMediaAtt |= KMediaAttLockable; @@ -2899,6 +2701,8 @@ #if defined(__DEMAND_PAGING__) && !defined(__WINS__) || DMediaPagingDevice::PageInRequest(*iCurrentReq) #endif //DEMAND_PAGING + // partition switching + || (GetEMmcPartitionMapping(iCurrentReq->Drive()->iPartitionNumber) != iSession->Partition()) ) { *aAllDone = EFalse; @@ -3745,6 +3549,12 @@ } r=DoWrite(); break; + case DLocalDrive::EDeleteNotify: + if(iCard->ExtendedCSD().ExtendedCSDRev() <5) + { + r=KErrNotSupported; + break; + } case DLocalDrive::EFormat: if (readOnly) { @@ -3908,6 +3718,13 @@ break; } +#ifdef EMMC_PARTITION_TEST_MODE_ENABLED + case KMmcSwitchPartition: + __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); + InvalidateCache(); + iSession->SetPartition((TInt) aParam1); + break; +#endif // EMMC_PARTITION_TEST_MODE_ENABLED default: r=KErrNotSupported; break;