📄 mvsata.c
字号:
/*******************************************************************************
*
* Copyright 2003,MARVELL SEMICONDUCTOR ISRAEL, LTD.
* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL.
* NO RIGHTS ARE GRANTED HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT
* OF MARVELL OR ANY THIRD PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE
* DISCRETION TO REQUEST THAT THIS CODE BE IMMEDIATELY RETURNED TO MARVELL.
* THIS CODE IS PROVIDED "AS IS". MARVELL MAKES NO WARRANTIES, EXPRESSED,
* IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, COMPLETENESS OR PERFORMANCE.
*
* MARVELL COMPRISES MARVELL TECHNOLOGY GROUP LTD. (MTGL) AND ITS SUBSIDIARIES,
* MARVELL INTERNATIONAL LTD. (MIL), MARVELL TECHNOLOGY, INC. (MTI), MARVELL
* SEMICONDUCTOR, INC. (MSI), MARVELL ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K.
* (MJKK), MARVELL SEMICONDUCTOR ISRAEL. (MSIL), MARVELL TAIWAN, LTD. AND
* SYSKONNECT GMBH.
********************************************************************************
* mvSata - C File for implementation of the core driver for MV88SX50XX.
*
* DESCRIPTION:
* None.
*
* DEPENDENCIES:
* mvOs.h
* mvSata.h.
* mvStorageDev.h
* mvRegs.h
*
* FILE REVISION NUMBER:
* $Revision: 1.21 $
*******************************************************************************/
#include "mvOs.h"
#include "mvSata.h"
#include "mvStorageDev.h"
#include "mvRegs.h"
/* Defines */
#define MV_SATA_PORT_PER_UNIT 4
#define MV_PHY_DET_STATE_NO_DEVICE 0
#define MV_PHY_DET_STATE_DEVICE_NO_PHY_COM 1
#define MV_PHY_DET_STATE_DEVICE_AND_PHY_COM 3
#define MV_PHY_DET_STATE_PHY_OFFLINE 4
#define MV_PHY_DET_CONTROL_START_NEGOTIATION 1
#define MV_PHY_DET_CONTROL_SHUTDOWN 4
#define MV_NEAR_END_LOOPBACK_TEST_WAIT_TIME 100 /* 100 uSec */
#define MV_FAR_END_LOOPBACK_TEST_WAIT_TIME 5 /* 5 uSec */
#define MV_PHY_COM_SETUP_WAIT 5000 /* 5 mili seconds */
#define MV_HARD_RESET_WAIT_ASSERT 25 /* 25 uSec */
#define MV_HARD_RESET_WAIT_NEGATE 2000 /* 2 mSec*/
#define MV_HARD_RESET_WAIT_READY 2000 /* ms to wait after HR*/
/* before disk access */
#define MV_HARD_RESET_WAIT_FOR_BUSY_LOOPS 10000
#define MV_HARD_RESET_WAIT_FOR_BUSY_LOOP_DELAY 1000
/* for the command result */
#define MV_EDMA_REQUEST_COMMANDS_NUM 11
/* Fix the watermark to the following default value */
#define MV_WATER_MARK_FIX 29 /* write 5'b11101 to bits 12:8*/
extern MV_BOOLEAN waitWhileStorageDevIsBusy(MV_SATA_ADAPTER *pAdapter,
MV_BUS_ADDR_T ioBaseAddr,
MV_U32 eDmaRegsOffset, MV_U32 loops,
MV_U32 delay);
extern void dumpAtaDeviceRegisters(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex, MV_BOOLEAN isEXT,
MV_STORAGE_DEVICE_REGISTERS *pRegisters);
extern MV_BOOLEAN _doSoftReset(MV_SATA_CHANNEL *pSataChannel);
MV_BOOLEAN isStorageDevReadyForPIO(MV_SATA_CHANNEL *pSataChannel);
MV_BOOLEAN executeNonUDMACommand(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex,
MV_NON_UDMA_PROTOCOL protocolType,
MV_BOOLEAN isEXT,
MV_U16_PTR bufPtr, MV_U32 count,
MV_U16 features,
MV_U16 sectorCount,
MV_U16 lbaLow, MV_U16 lbaMid,
MV_U16 lbaHigh, MV_U8 device,
MV_U8 command);
extern MV_BOOLEAN waitForDRQ(MV_SATA_ADAPTER* pAdapter,
MV_BUS_ADDR_T ioBaseAddr,
MV_U32 eDmaRegsOffset, MV_U32 loops,
MV_U32 delay);
static MV_BOOLEAN _checkSStatusAfterHReset(MV_SATA_ADAPTER* pAdapter,
MV_U8 channelIndex);
#ifdef MV_LOGGER
void _dumpPCIRegs(MV_SATA_ADAPTER *pAdapter);
void _dumpEDMARegs(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
void _dumpChannelQueues(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
void _dumpSataRegs(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
#else
#define _dumpPCIRegs(p)
#define _dumpEDMARegs(p,i)
#define _dumpChannelQueues(p,i)
#define _dumpSataRegs(p,i)
#endif
/* write ATA command register entry in a request entry */
#define WRITE_ATA_COMMAND_REG(addr, data, reg, isLast) \
do{ \
*(addr) = MV_CPU_TO_LE16((((MV_U8)(data)) & 0xff) | ((reg) << 8) | (isLast)); \
} while(0)
#define MV_CHANNEL_INDEX(unit, port) (((unit) << 2) | (port))
/* Typedefs */
typedef struct mvDmaRequestQueueEntry
{
/* Fields set by CORE driver */
volatile MV_U32 prdLowAddr;
volatile MV_U32 prdHighAddr;
volatile MV_U16 controlFlags;
volatile MV_U16 command[MV_EDMA_REQUEST_COMMANDS_NUM];
} MV_DMA_REQUEST_QUEUE_ENTRY;
typedef struct mvDmaResponseQueueEntry
{
/* Fields set by hardware */
volatile MV_U16 commandTag;
volatile MV_U16 responseFlags;
volatile MV_U32 timeStamp;
} MV_DMA_RESPONSE_QUEUE_ENTRY;
/* local functions */
/*static*/ MV_BOOLEAN waitForBusyAfterHReset(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex);
static void unmaskEdmaInterrupts(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void maskEdmaInterrupts(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void writeEdmaRequestEntry(MV_DMA_REQUEST_QUEUE_ENTRY *pReqEntry,
MV_SATA_CHANNEL *mvSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry,
MV_UDMA_COMMAND_PARAMS *pUdmaParams);
static void handleEdmaFailedCommand(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex, MV_U16 eDmaErrorCause);
static void handleEdmaResponse(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex,
MV_DMA_RESPONSE_QUEUE_ENTRY *eDmaResponse);
#ifdef MV_SATA_C2C_COMM
static void handleBmDMAInterrupt(MV_SATA_ADAPTER *pAdapter,
MV_BUS_ADDR_T ioBaseAddr,
MV_SATA_CHANNEL *pSataChannel,
MV_U8 channelIndex,
MV_U32 edmaError);
#endif
static void handleEdmaInterrupt(MV_SATA_ADAPTER *pAdapter, MV_U8 sataUnit,
MV_U8 port, MV_U32 rspInPtr,MV_U32 responseDone,
MV_U32 edmaError, MV_U32 unitCause);
static void handleDeviceInterrupt(MV_SATA_ADAPTER *pAdapter, MV_U8 sataUnit,
MV_U8 port);
#ifdef MV_SATA_C2C_COMM
static void handleC2CInterrupt(MV_SATA_CHANNEL *pSataChannel);
#endif
static void handlePIOInterrupt(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry);
static MV_BOOLEAN transferPIOData(MV_SATA_CHANNEL *pSataChannel,
MV_NONE_UDMA_COMMAND_PARAMS *pNoneUdmaCommandParams);
static void completePIOCommand(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry,
MV_BOOLEAN failed);
static MV_BOOLEAN resetEdmaChannel(MV_SATA_CHANNEL *pSataChannel);
static void flushDmaQueue(MV_SATA_CHANNEL *pSataChannel,
MV_FLUSH_TYPE flushType, MV_COMPLETION_TYPE, MV_U16);
static void _fixPhyParams(MV_SATA_ADAPTER *pMvSataAdapter, MV_U8 channelIndex);
static void _channelHardReset(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void _establishSataComm(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void _establishSataCommAll(MV_SATA_ADAPTER *pAdapter);
void _setActivePMPort(MV_SATA_CHANNEL *pSataChannel, MV_U8 PMPort);
static void revertSataHCRegs (MV_SATA_ADAPTER *pAdapter);
static void revertFlashInterfaceRegs (MV_SATA_ADAPTER *pAdapter);
static void revertPCIInterfaceRegs (MV_SATA_ADAPTER *pAdapter);
static void commandsQueueAddTail(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry);
static void commandsQueueRemove(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry);
static void addCommand(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry,
MV_QUEUE_COMMAND_INFO *pCommandInfo);
static void removeCommand(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry);
static void enableSaDevInterrutps(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
void disableSaDevInterrutps(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void activateEdma(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void deactivateEdma(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex);
static void EdmaReqQueueInsert(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry,
MV_UDMA_COMMAND_PARAMS *pUdmaParams);
static MV_BOOLEAN sendNoneUdmaCommand(MV_SATA_CHANNEL *pSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry);
static MV_VOID _doAutoFlush(MV_SATA_CHANNEL *pSataChannel);
#ifdef MV_SATA_C2C_COMM
/* Channel 2 Channel */
static MV_BOOLEAN sendVendorUniqueFIS(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex,
MV_U32 *vendorUniqueBuffer,
MV_U8 numOfDWords);
static void activateBMDmaMode(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex,
MV_U32 prdTableHi, MV_U32 prdTableLow,
MV_UDMA_TYPE dmaType);
#endif
#ifdef MV_SATA_IO_GRANULARITY
static void setIoGranularityCount(MV_SATA_ADAPTER *pAdapter,
MV_U8 transId,
MV_U8 counter);
static MV_U8 readIoGranularityCount(MV_SATA_ADAPTER *pAdapter,
MV_U8 transId);
static void iogInterrupt(MV_SATA_ADAPTER *pAdapter,
MV_BUS_ADDR_T ioBaseAddr,
MV_U32 mainCause);
static void checkIogCompletion(MV_SATA_ADAPTER *pAdapter,
MV_U32 iogCause, MV_U8 offset);
static void checkIogBit(MV_SATA_ADAPTER *pAdapter,
MV_U8 bitOffset,
MV_U8 value);
static MV_BOOLEAN iogReset(MV_SATA_ADAPTER *pAdapter);
#endif
/* Calculate the base address of the registers for a SATA channel */
MV_U32 edmaRegOffst[MV_SATA_CHANNELS_NUM] = {0x22000, 0x24000, 0x26000, 0x28000,
0x32000, 0x34000, 0x36000, 0x38000};
#define getEdmaRegOffset(x) edmaRegOffst[(x)]
MV_BOOLEAN waitForBusyAfterHReset(MV_SATA_ADAPTER *pAdapter,
MV_U8 channelIndex)
{
MV_U32 i;
MV_U8 ATAstatus;
mvMicroSecondsDelay(pAdapter, MV_HARD_RESET_WAIT_READY);
for (i = MV_HARD_RESET_WAIT_READY; i < 5000000; i+= 10000)
{
ATAstatus = MV_REG_READ_BYTE(pAdapter->adapterIoBaseAddress,
getEdmaRegOffset(channelIndex) +
MV_ATA_DEVICE_STATUS_REG_OFFSET);
if ((ATAstatus & MV_ATA_BUSY_STATUS) == 0)
{
return MV_TRUE;
}
mvMicroSecondsDelay(pAdapter, 10000);
}
mvLogMsg(MV_CORE_DRIVER_LOG_ID, MV_DEBUG_ERROR, " %d %d: in Channel Hard Rese"
"t wait for busy, ATA STATUS=0x%02x\n", pAdapter->adapterId,
channelIndex, ATAstatus);
return MV_FALSE;
}
static void unmaskEdmaInterrupts(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex)
{
MV_REG_WRITE_DWORD(pAdapter->adapterIoBaseAddress,
getEdmaRegOffset(channelIndex) +
MV_EDMA_INTERRUPT_ERROR_CAUSE_REG_OFFSET,
0);
if (pAdapter->sataAdapterGeneration == MV_SATA_GEN_I)
{
/* Unmask EDMA self disable (bit 8), device connect and disconnect */
MV_REG_WRITE_DWORD(pAdapter->adapterIoBaseAddress,
getEdmaRegOffset(channelIndex) +
MV_EDMA_INTERRUPT_ERROR_MASK_REG_OFFSET,
MV_BIT8 | MV_BIT4 | MV_BIT3);
}
else
{
/* Unmask EDMA self disable (bit 7), device connect and disconnect */
MV_REG_WRITE_DWORD(pAdapter->adapterIoBaseAddress,
getEdmaRegOffset(channelIndex) +
MV_EDMA_INTERRUPT_ERROR_MASK_REG_OFFSET,
MV_BIT8 | MV_BIT7 | MV_BIT4 | MV_BIT3);
}
}
static void maskEdmaInterrupts(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex)
{
MV_REG_WRITE_DWORD(pAdapter->adapterIoBaseAddress,
getEdmaRegOffset(channelIndex) +
MV_EDMA_INTERRUPT_ERROR_MASK_REG_OFFSET,
0);
}
/* Global Variables */
MV_BOOLEAN mvAutoFlushOnError = MV_FALSE;
/*******************************************************************************
* writeEdmaRequestEntry - Write a CRQB (COMMAND REQUEST QUEUE BLOCK)
*
* DESCRIPTION:
* write one CRQB for an EDMA request queue.
*
* INPUT:
* pReqEntry - pointer to the CRQB area on the system memory
* (HW reqeust Queue).
* mvSataChannel - pointer to the channel data structure
* pCommandEntry - pointer to the command entry data structure
* (SW request Queue).
*
* RETURN:
* None
*
* COMMENTS:
* None.
*
*******************************************************************************/
static void writeEdmaRequestEntry(MV_DMA_REQUEST_QUEUE_ENTRY *pReqEntry,
MV_SATA_CHANNEL *mvSataChannel,
MV_QUEUED_COMMAND_ENTRY *pCommandEntry,
MV_UDMA_COMMAND_PARAMS *pUdmaParams)
{
MV_U16 ControlFlags = 0;
volatile MV_U16 *pCommand = &pReqEntry->command[0];
MV_U8 ATACommand = 0;
pReqEntry->prdLowAddr = MV_CPU_TO_LE32(pUdmaParams->prdLowAddr);
pReqEntry->prdHighAddr = MV_CPU_TO_LE32(pUdmaParams->prdHighAddr);
/* Set the direction of the transaction (read/write) */
if (pUdmaParams->readWrite == MV_UDMA_TYPE_READ)
{
ControlFlags |= 0x1; /* Device to system memory */
}
ControlFlags |= (pCommandEntry->commandTag << 1); /* the tag will be used also */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -