On Fri, Feb 10, 2012 at 12:45 AM, Girish K S <girish.shivananjappa@xxxxxxxxxx> wrote: > On 2 February 2012 10:27, Vinayak Holikatti <vinholikatti@xxxxxxxxx> wrote: >> From: Santosh Yaraganavi <santoshsy@xxxxxxxxx> >> >> This patch adds support for Universal Flash Storage(UFS) >> host controllers. The UFS host controller driver >> includes host controller initialization method. >> >> The Initialization process involves following steps: >> - Initiate UFS Host Controller initialization process by writing >> to Host controller enable register >> - Configure UFS Host controller registers with host memory space >> datastructure offsets. >> - Unipro link startup procedure >> - Check for connected device >> - Configure UFS host controller to process requests >> - Enable required interrupts >> - Configure interrupt aggregation >> >> Signed-off-by: Santosh Yaraganavi <santoshsy@xxxxxxxxx> >> Signed-off-by: Vinayak Holikatti <vinholikatti@xxxxxxxxx> >> Reviewed-by: Arnd Bergmann <arnd@xxxxxxxx> >> Reviewed-by: Saugata Das <saugata.das@xxxxxxxxxx> >> Reviewed-by: Vishak G <vishak.g@xxxxxxxxxxx> >> Reviewed-by: Girish K S <girish.shivananjappa@xxxxxxxxxx> >> --- >> drivers/scsi/Kconfig | 1 + >> drivers/scsi/Makefile | 1 + >> drivers/scsi/ufs/Kconfig | 49 ++ >> drivers/scsi/ufs/Makefile | 2 + >> drivers/scsi/ufs/ufs.h | 203 +++++++++ >> drivers/scsi/ufs/ufshcd.c | 1091 +++++++++++++++++++++++++++++++++++++++++++++ >> drivers/scsi/ufs/ufshci.h | 360 +++++++++++++++ >> 7 files changed, 1707 insertions(+), 0 deletions(-) >> create mode 100644 drivers/scsi/ufs/Kconfig >> create mode 100644 drivers/scsi/ufs/Makefile >> create mode 100644 drivers/scsi/ufs/ufs.h >> create mode 100644 drivers/scsi/ufs/ufshcd.c >> create mode 100644 drivers/scsi/ufs/ufshci.h >> >> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig >> index 16570aa..477a91a 100644 >> --- a/drivers/scsi/Kconfig >> +++ b/drivers/scsi/Kconfig >> @@ -619,6 +619,7 @@ config SCSI_ARCMSR >> >> source "drivers/scsi/megaraid/Kconfig.megaraid" >> source "drivers/scsi/mpt2sas/Kconfig" >> +source "drivers/scsi/ufs/Kconfig" >> >> config SCSI_HPTIOP >> tristate "HighPoint RocketRAID 3xxx/4xxx Controller support" >> diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile >> index 2b88749..c832974 100644 >> --- a/drivers/scsi/Makefile >> +++ b/drivers/scsi/Makefile >> @@ -108,6 +108,7 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o >> obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ >> obj-$(CONFIG_MEGARAID_SAS) += megaraid/ >> obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ >> +obj-$(CONFIG_SCSI_UFSHCD) += ufs/ >> obj-$(CONFIG_SCSI_ACARD) += atp870u.o >> obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o >> obj-$(CONFIG_SCSI_GDTH) += gdth.o >> diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig >> new file mode 100644 >> index 0000000..8f27f9d >> --- /dev/null >> +++ b/drivers/scsi/ufs/Kconfig >> @@ -0,0 +1,49 @@ >> +# >> +# Kernel configuration file for the UFS Host Controller >> +# >> +# This code is based on drivers/scsi/ufs/Kconfig >> +# Copyright (C) 2011 Samsung Samsung India Software Operations >> +# >> +# Santosh Yaraganavi <santosh.sy@xxxxxxxxxxx> >> +# Vinayak Holikatti <h.vinayak@xxxxxxxxxxx> >> + >> +# This program is free software; you can redistribute it and/or >> +# modify it under the terms of the GNU General Public License >> +# as published by the Free Software Foundation; either version 2 >> +# of the License, or (at your option) any later version. >> + >> +# This program is distributed in the hope that it will be useful, >> +# but WITHOUT ANY WARRANTY; without even the implied warranty of >> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> +# GNU General Public License for more details. >> + >> +# NO WARRANTY >> +# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR >> +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT >> +# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, >> +# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is >> +# solely responsible for determining the appropriateness of using and >> +# distributing the Program and assumes all risks associated with its >> +# exercise of rights under this Agreement, including but not limited to >> +# the risks and costs of program errors, damage to or loss of data, >> +# programs or equipment, and unavailability or interruption of operations. >> + >> +# DISCLAIMER OF LIABILITY >> +# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY >> +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> +# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND >> +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> +# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED >> +# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES >> + >> +# You should have received a copy of the GNU General Public License >> +# along with this program; if not, write to the Free Software >> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, >> +# USA. >> + >> +config SCSI_UFSHCD >> + tristate "Universal Flash Storage host controller driver" >> + depends on PCI && SCSI >> + ---help--- >> + This is a generic driver which supports PCIe UFS Host controllers. >> diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile >> new file mode 100644 >> index 0000000..adf7895 >> --- /dev/null >> +++ b/drivers/scsi/ufs/Makefile >> @@ -0,0 +1,2 @@ >> +# UFSHCD makefile >> +obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o >> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h >> new file mode 100644 >> index 0000000..96b5cae >> --- /dev/null >> +++ b/drivers/scsi/ufs/ufs.h >> @@ -0,0 +1,203 @@ >> +/* >> + * Universal Flash Storage Host controller driver >> + * >> + * This code is based on drivers/scsi/ufs/ufs.h >> + * Copyright (C) 2011-2012 Samsung India Software Operations >> + * >> + * Santosh Yaraganavi <santosh.sy@xxxxxxxxxxx> >> + * Vinayak Holikatti <h.vinayak@xxxxxxxxxxx> >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * as published by the Free Software Foundation; either version 2 >> + * of the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * NO WARRANTY >> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR >> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT >> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, >> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is >> + * solely responsible for determining the appropriateness of using and >> + * distributing the Program and assumes all risks associated with its >> + * exercise of rights under this Agreement, including but not limited to >> + * the risks and costs of program errors, damage to or loss of data, >> + * programs or equipment, and unavailability or interruption of operations. >> + >> + * DISCLAIMER OF LIABILITY >> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY >> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND >> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED >> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES >> + >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, >> + * USA. >> + */ >> + >> +#ifndef _UFS_H >> +#define _UFS_H >> + >> +#define TASK_REQ_UPIU_SIZE_DWORDS 8 >> +#define TASK_RSP_UPIU_SIZE_DWORDS 8 >> + >> +#define MAX_CDB_SIZE 16 >> +#define ALIGNED_UPIU_SIZE 128 >> + >> +#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ >> + ((byte3 << 24) | (byte2 << 16) |\ >> + (byte1 << 8) | (byte0)) >> + >> +/* >> + * UFS Protocol Information Unit related definitions >> + */ >> + >> +/* Task management functions */ >> +enum { >> + UFS_ABORT_TASK = 0x01, >> + UFS_ABORT_TASK_SET = 0x02, >> + UFS_CLEAR_TASK_SET = 0x04, >> + UFS_LOGICAL_RESET = 0x08, >> + UFS_QUERY_TASK = 0x80, >> + UFS_QUERY_TASK_SET = 0x81 >> +}; >> + >> +/* UTP UPIU Transaction Codes Initiator to Target */ >> +enum { >> + UPIU_TRANSACTION_NOP_OUT = 0x00, >> + UPIU_TRANSACTION_COMMAND = 0x01, >> + UPIU_TRANSACTION_DATA_OUT = 0x02, >> + UPIU_TRANSACTION_TASK_REQ = 0x04, >> + UPIU_TRANSACTION_QUERY_REQ = 0x26 >> +}; >> + >> +/* UTP UPIU Transaction Codes Target to Initiator */ >> +enum { >> + UPIU_TRANSACTION_NOP_IN = 0x20, >> + UPIU_TRANSACTION_RESPONSE = 0x21, >> + UPIU_TRANSACTION_DATA_IN = 0x22, >> + UPIU_TRANSACTION_TASK_RSP = 0x24, >> + UPIU_TRANSACTION_READY_XFER = 0x31, >> + UPIU_TRANSACTION_QUERY_RSP = 0x36 >> +}; >> + >> +/* UPIU Read/Write flags */ >> +enum { >> + UPIU_CMD_FLAGS_READ = 0x40, >> + UPIU_CMD_FLAGS_WRITE = 0x20 >> + >> +}; >> + >> +/* UPIU Task Attributes */ >> +enum { >> + UPIU_TASK_ATTR_SIMPLE = 0x00, >> + UPIU_TASK_ATTR_ORDERED = 0x01, >> + UPIU_TASK_ATTR_HEADQ = 0x02, >> + UPIU_TASK_ATTR_ACA = 0x03 >> +}; >> + >> +/* UTP QUERY Transaction Specific Fields OpCode */ >> +enum { >> + UPIU_QUERY_OPCODE_NOP = 0x0, >> + UPIU_QUERY_OPCODE_READ_DESC = 0x1, >> + UPIU_QUERY_OPCODE_WRITE_DESC = 0x2, >> + UPIU_QUERY_OPCODE_READ_ATTR = 0x3, >> + UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4, >> + UPIU_QUERY_OPCODE_READ_FLAG = 0x5, >> + UPIU_QUERY_OPCODE_SET_FLAG = 0x6, >> + UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, >> + UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8 >> +}; >> + >> +/* UTP Transfer Request Command Type (CT) */ >> +enum { >> + UPIU_COMMAND_SET_TYPE_SCSI = 0x0, >> + UPIU_COMMAND_SET_TYPE_UFS = 0x1, >> + UPIU_COMMAND_SET_TYPE_QUERY = 0x2 >> +}; >> + >> +enum { >> + MASK_SCSI_STATUS = 0xFF, >> + MASK_TASK_RESPONSE = 0xFF00, >> + MASK_RSP_UPIU_RESULT = 0xFFFF >> +}; >> + >> +/** >> + * struct utp_upiu_header - UPIU header structure >> + * @dword_0: UPIU header DW-0 >> + * @dword_1: UPIU header DW-1 >> + * @dword_2: UPIU header DW-2 >> + */ >> +struct utp_upiu_header { >> + u32 dword_0; >> + u32 dword_1; >> + u32 dword_2; >> +}; >> + >> +/** >> + * struct utp_upiu_cmd - Command UPIU structure >> + * @header: UPIU header structure DW-0 to DW-2 >> + * @data_transfer_len: Data Transfer Length DW-3 >> + * @cdb: Command Descriptor Block CDB DW-4 to DW-7 >> + */ >> +struct utp_upiu_cmd { >> + struct utp_upiu_header header; >> + u32 exp_data_transfer_len; >> + u8 cdb[MAX_CDB_SIZE]; >> +}; >> + >> +/** >> + * struct utp_upiu_rsp - Response UPIU structure >> + * @header: UPIU header DW-0 to DW-2 >> + * @residual_transfer_count: Residual transfer count DW-3 >> + * @reserved: Reserver DW-4 to DW-7 >> + * @sense_data_len: Sense data length DW-8 U16 >> + * @sense_data: Sense data field DW-8 to DW-12 >> + */ >> +struct utp_upiu_rsp { >> + struct utp_upiu_header header; >> + u32 residual_transfer_count; >> + u32 reserved[4]; >> + u16 sense_data_len; >> + u8 sense_data[18]; >> +}; >> + >> +/** >> + * struct utp_upiu_task_req - Task request UPIU structure >> + * @header - UPIU header structure DW0 to DW-2 >> + * @input_param1: Input param 1 DW-3 >> + * @input_param2: Input param 2 DW-4 >> + * @input_param3: Input param 3 DW-5 >> + * @reserved: Reserver DW-6 to DW-7 >> + */ >> +struct utp_upiu_task_req { >> + struct utp_upiu_header header; >> + u32 input_param1; >> + u32 input_param2; >> + u32 input_param3; >> + u32 reserved[2]; >> +}; >> + >> +/** >> + * struct utp_upiu_task_rsp - Task Management Response UPIU structure >> + * @header: UPIU header structure DW0-DW-2 >> + * @output_param1: Ouput param 1 DW3 >> + * @output_param2: Output param 2 DW4 >> + * @reserved: Reserver DW-5 to DW-7 >> + */ >> +struct utp_upiu_task_rsp { >> + struct utp_upiu_header header; >> + u32 output_param1; >> + u32 output_param2; >> + u32 reserved[3]; >> +}; >> + >> +#endif /* End of Header */ >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c >> new file mode 100644 >> index 0000000..c82eeea >> --- /dev/null >> +++ b/drivers/scsi/ufs/ufshcd.c >> @@ -0,0 +1,1091 @@ >> +/* >> + * Universal Flash Storage Host controller driver >> + * >> + * This code is based on drivers/scsi/ufs/ufshcd.c >> + * Copyright (C) 2011-2012 Samsung India Software Operations >> + * >> + * Santosh Yaraganavi <santosh.sy@xxxxxxxxxxx> >> + * Vinayak Holikatti <h.vinayak@xxxxxxxxxxx> >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * as published by the Free Software Foundation; either version 2 >> + * of the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * NO WARRANTY >> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR >> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT >> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, >> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is >> + * solely responsible for determining the appropriateness of using and >> + * distributing the Program and assumes all risks associated with its >> + * exercise of rights under this Agreement, including but not limited to >> + * the risks and costs of program errors, damage to or loss of data, >> + * programs or equipment, and unavailability or interruption of operations. >> + >> + * DISCLAIMER OF LIABILITY >> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY >> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND >> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED >> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES >> + >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, >> + * USA. >> + */ >> + >> +#include <linux/module.h> >> +#include <linux/kernel.h> >> +#include <linux/init.h> >> +#include <linux/pci.h> >> +#include <linux/interrupt.h> >> +#include <linux/io.h> >> +#include <linux/delay.h> >> +#include <linux/slab.h> >> +#include <linux/spinlock.h> >> +#include <linux/workqueue.h> >> +#include <linux/errno.h> >> +#include <linux/types.h> >> +#include <linux/wait.h> >> + >> +#include <asm/irq.h> >> +#include <asm/byteorder.h> >> +#include <scsi/scsi.h> >> +#include <scsi/scsi_cmnd.h> >> +#include <scsi/scsi_host.h> >> +#include <scsi/scsi_dbg.h> >> + >> +#include "ufs.h" >> +#include "ufshci.h" >> + >> +#define UFSHCD "ufshcd" >> +#define UFSHCD_DRIVER_VERSION "0.1" >> + >> +#ifndef NULL >> +#define NULL 0 >> +#endif /* NULL */ >> + >> +#define BYTES_TO_DWORDS(p) (p >> 2) >> +#define UFSHCD_MMIO_BASE (hba->mmio_base) >> + >> +enum { >> + UFSHCD_MAX_CHANNEL = 1, >> + UFSHCD_MAX_ID = 1, >> + UFSHCD_MAX_LUNS = 8, >> + UFSHCD_CAN_QUEUE = 32, >> + BYTES_128 = 128, >> + BYTES_1024 = 1024 >> +}; >> + >> +/* UFSHCD states */ >> +enum { >> + UFSHCD_STATE_OPERATIONAL, >> + UFSHCD_STATE_RESET, >> + UFSHCD_STATE_ERROR >> +}; >> + >> +/* Interrupt configuration options */ >> +enum { >> + UFSHCD_INT_DISABLE, >> + UFSHCD_INT_ENABLE, >> + UFSHCD_INT_CLEAR >> +}; >> + >> +/* Interrupt aggregation options */ >> +enum { >> + INT_AGGR_RESET, >> + INT_AGGR_CONFIG >> +}; >> + >> +/** >> + * struct uic_command - UIC command structure >> + * @command: UIC command >> + * @argument1: UIC command argument 1 >> + * @argument2: UIC command argument 2 >> + * @argument3: UIC command argument 3 >> + * @cmd_active: Indicate if UIC command is outstanding >> + * @result: UIC command result >> + * @callback: routine to be called when UIC command completes >> + */ >> +struct uic_command { >> + u32 command; >> + u32 argument1; >> + u32 argument2; >> + u32 argument3; >> + int cmd_active; >> + int result; >> +}; >> + >> +/** >> + * struct ufs_hba - per adapter private structure >> + * @mmio_base: UFSHCI base register address >> + * @ucdl_virt_addr: UFS Command Descriptor virtual address >> + * @utrdl_virt_addr: UTP Transfer Request Descriptor virtual address >> + * @utmrdl_virt_addr: UTP Task Management Descriptor virtual address >> + * @utrdl_virt_addr_aligned: UTRD Aligned vitual address >> + * @utmrdl_virt_addr_aligned: UTMRD Aligned virtual address >> + * @ucdl_size: Memory size of UCD command block >> + * @utrdl_size: Memory size of UTRDL block >> + * @utmrdl_size: Memory size of UTMRDL block >> + * @ucdl_dma_addr: UFS Command Descriptor DMA address >> + * @utrdl_dma_addr: UTRDL DMA address >> + * @utmrdl_dma_addr: UTMRDL DMA address >> + * @utrdl_dma_addr_aligned: UTRDL aligned DMA address >> + * @utmrdl_dma_addr_aligned: UTMRDL aligned DMA address >> + * @ucdl_dma_addr_aligned: UCD aligned DMA address >> + * @dma_size: >> + * @host: Scsi_Host instance of the driver >> + * @pdev: PCI device handle >> + * @lrb: local reference block >> + * @capabilities: UFS Controller Capabilities >> + * @nutrs: Transfer Request Queue depth supported by controller >> + * @nutmrs: Task Management Queue depth supported by controller >> + * @active_uic_cmd: handle of active UIC command >> + * @ufshcd_state: UFSHCD states >> + * @int_enable_mask: Interrupt Mask Bits >> + * @uic_workq: Work queue for UIC completion handling >> + */ >> +struct ufs_hba { >> + void __iomem *mmio_base; >> + >> + /* Virtual memory reference */ >> + void *ucdl_virt_addr; >> + void *utrdl_virt_addr; >> + void *utmrdl_virt_addr; >> + void *utrdl_virt_addr_aligned; >> + void *utmrdl_virt_addr_aligned; >> + void *ucdl_virt_addr_aligned; >> + >> + size_t ucdl_size; >> + size_t utrdl_size; >> + size_t utmrdl_size; >> + >> + /* DMA memory reference */ >> + dma_addr_t ucdl_dma_addr; >> + dma_addr_t utrdl_dma_addr; >> + dma_addr_t utmrdl_dma_addr; >> + dma_addr_t utrdl_dma_addr_aligned; >> + dma_addr_t utmrdl_dma_addr_aligned; >> + dma_addr_t ucdl_dma_addr_aligned; >> + >> + size_t dma_size; >> + >> + struct Scsi_Host *host; >> + struct pci_dev *pdev; >> + >> + struct ufshcd_lrb *lrb; >> + >> + u32 capabilities; >> + int nutrs; >> + int nutmrs; >> + u32 ufs_version; >> + >> + struct uic_command active_uic_cmd; >> + >> + u32 ufshcd_state; >> + u32 int_enable_mask; >> + >> + /* Work Queues */ >> + struct work_struct uic_workq; >> +}; >> + >> +/** >> + * struct ufshcd_lrb - command control block >> + * @utr_descriptor_ptr: UTRD address of the command >> + * @ucd_cmd_ptr: UCD address of the command >> + * @ucd_rsp_ptr: Response UPIU address for this command >> + * @ucd_prdt_ptr: PRDT address of the command >> + */ >> +struct ufshcd_lrb { >> + struct utp_transfer_req_desc *utr_descriptor_ptr; >> + struct utp_upiu_cmd *ucd_cmd_ptr; >> + struct utp_upiu_rsp *ucd_rsp_ptr; >> + struct ufshcd_sg_entry *ucd_prdt_ptr; >> +}; >> + >> +/** >> + * ufshcd_get_ufs_version - Get the UFS version supported by the HBA >> + * @hba - Pointer to adapter instance >> + * >> + * Returns UFSHCI version supported by the controller >> + */ >> +static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) >> +{ >> + return readl(UFSHCD_MMIO_BASE + REG_UFS_VERSION); >> +} >> + >> +/** >> + * ufshcd_is_device_present - Check if any device connected to >> + * the host controller >> + * @reg_hcs - host controller status register value >> + * >> + * Returns 0 if device present, non-zeo if no device detected >> + */ >> +static inline int ufshcd_is_device_present(u32 reg_hcs) >> +{ >> + return (DEVICE_PRESENT & reg_hcs) ? 0 : -1; >> +} >> + >> +/** >> + * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY >> + * @reg: Register value of host controller status >> + * >> + * Returns integer, 0 on Success and positive value if failed >> + */ >> +static inline int ufshcd_get_lists_status(u32 reg) >> +{ >> + /* >> + * The mask 0xFF is for the following HCS register bits >> + * Bit Description >> + * 0 Device Present >> + * 1 UTRLRDY >> + * 2 UTMRLRDY >> + * 3 UCRDY >> + * 4 HEI >> + * 5 DEI >> + * 6-7 reserved >> + */ >> + return (((reg) & (0xFF)) >> 1) ^ (0x07); >> +} >> + >> +/** >> + * ufshcd_get_uic_cmd_result - Get the UIC command result >> + * @hba: Pointer to adapter instance >> + * >> + * This function gets the result of UIC command completion >> + * Returns 0 on success, non zero value on error >> + */ >> +static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) >> +{ >> + return readl(UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_2) & >> + MASK_UIC_COMMAND_RESULT; >> +} >> + >> +/** >> + * ufshcd_free_hba_memory - Free allocated memory for LRB request >> + * and task lists >> + * @hba: Pointer to adapter instance >> + */ >> +static inline void ufshcd_free_hba_memory(struct ufs_hba *hba) >> +{ >> + kfree(hba->lrb); >> + hba->lrb = NULL; >> + >> + if (hba->utmrdl_virt_addr_aligned) { >> + dma_free_coherent(&hba->pdev->dev, hba->utmrdl_size, >> + hba->utmrdl_virt_addr, hba->utmrdl_dma_addr); >> + hba->utmrdl_virt_addr = NULL; >> + hba->utmrdl_virt_addr_aligned = NULL; >> + } >> + >> + if (hba->utrdl_virt_addr_aligned) { >> + dma_free_coherent(&hba->pdev->dev, hba->utrdl_size, >> + hba->utrdl_virt_addr, hba->utrdl_dma_addr); >> + hba->utrdl_virt_addr = NULL; >> + hba->utrdl_virt_addr_aligned = NULL; >> + } >> + >> + if (hba->ucdl_virt_addr_aligned) { >> + dma_free_coherent(&hba->pdev->dev, hba->ucdl_size, >> + hba->ucdl_virt_addr, hba->ucdl_dma_addr); >> + hba->ucdl_virt_addr = NULL; >> + hba->ucdl_virt_addr_aligned = NULL; >> + } >> +} >> + >> +/** >> + * ufshcd_config_int_aggr - Configure interrupt aggregation values >> + * currently there is no use case where we want to configure >> + * interrupt aggregation dynamically. So to configure interrupt >> + * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and >> + * INT_AGGR_TIMEOUT_VALUE are used. >> + * @hba: per adapter instance >> + * @option: Interrupt aggregation option >> + */ >> +static inline void >> +ufshcd_config_int_aggr(struct ufs_hba *hba, int option) >> +{ >> + switch (option) { >> + case INT_AGGR_RESET: >> + writel((INT_AGGR_ENABLE | >> + INT_AGGR_COUNTER_AND_TIMER_RESET), >> + (UFSHCD_MMIO_BASE + >> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL)); >> + break; >> + case INT_AGGR_CONFIG: >> + writel((INT_AGGR_ENABLE | >> + INT_AGGR_PARAM_WRITE | >> + INT_AGGR_COUNTER_THRESHOLD_VALUE | >> + INT_AGGR_TIMEOUT_VALUE), >> + (UFSHCD_MMIO_BASE + >> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL)); >> + break; >> + } >> +} >> + >> +/** >> + * ufshcd_hba_stop - put the controller in reset state >> + * @hba: per adapter instance >> + */ >> +static inline void ufshcd_hba_stop(struct ufs_hba *hba) >> +{ >> + writel(0, (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE)); >> +} >> + >> +/** >> + * ufshcd_hba_capabilities - Read controller capabilities >> + * @hba: per adapter instance >> + */ >> +static inline void ufshcd_hba_capabilities(struct ufs_hba *hba) >> +{ >> + u32 capabilities; >> + >> + capabilities = >> + readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_CAPABILITIES); >> + hba->capabilities = capabilities; >> + >> + /* nutrs and nutmrs are 0 based values */ >> + hba->nutrs = (capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1; >> + hba->nutmrs = >> + ((capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1; >> +} >> + >> +/** >> + * ufshcd_send_uic_command - Send UIC commands to unipro layers >> + * @hba: per adapter instance >> + * @uic_command: UIC command >> + */ >> +static inline void >> +ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd) >> +{ >> + /* Clear interrupt status register */ >> + writel((readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS)), >> + (UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS)); >> + >> + /* Write Args */ >> + writel(uic_cmnd->argument1, >> + (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_1)); >> + writel(uic_cmnd->argument2, >> + (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_2)); >> + writel(uic_cmnd->argument3, >> + (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_3)); >> + >> + /* Write UIC Cmd */ >> + writel((uic_cmnd->command & COMMAND_OPCODE_MASK), >> + (UFSHCD_MMIO_BASE + REG_UIC_COMMAND)); >> +} >> + >> +/** >> + * ufshcd_int_config - enable/disable interrupts >> + * @hba: per adapter instance >> + * @option: interrupt option >> + */ >> +static void ufshcd_int_config(struct ufs_hba *hba, u32 option) >> +{ >> + switch (option) { >> + case UFSHCD_INT_ENABLE: >> + writel(hba->int_enable_mask, >> + (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE)); >> + break; >> + case UFSHCD_INT_DISABLE: >> + if (UFSHCI_VERSION_10 == hba->ufs_version) >> + writel(readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE), >> + (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE)); >> + else >> + writel(0, (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE)); >> + break; >> + default: >> + dev_err(&hba->pdev->dev, "Invalid interrupt option\n"); >> + break; >> + } /* end of switch */ >> +} >> + >> +/** >> + * ufshcd_memory_alloc - allocate memory for host memory space data structures >> + * @hba: per adapter instance >> + * >> + * 1) Allocate DMA memory for Command Descriptor array >> + * Each command descriptor consist of Command UPIU, Response UPIU and PRDT >> + * 2) Align allocated command descriptor address to 128 byte align. >> + * 3) Allocate DMA memory for UTP Transfer Request Descriptor List (UTRDL). >> + * 4) Align UTRDL address to 1KB (UFSHCI spec) >> + * 5) Allocate DMA memory for UTP Task Management Request Descriptor List >> + * (UTMRDL) >> + * 6) Align UTMRDL address to 1KB (UFSHCI spec) >> + * 7) Allocate the memory for local reference block(lrb). >> + * >> + * Returns 0 for success, non-zero in case of failure >> + */ >> +static int ufshcd_memory_alloc(struct ufs_hba *hba) >> +{ >> + /* >> + * Allocate memory for UTP command descriptors. >> + * UFSHCI requires 128 byte alignement of UCD and >> + * 64 byte alignement for PRDT. So allocating extra 128 bytes >> + */ >> + hba->ucdl_size = >> + (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs) + BYTES_128; >> + hba->ucdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev, >> + hba->ucdl_size, >> + &hba->ucdl_dma_addr, >> + GFP_KERNEL); >> + if (NULL == hba->ucdl_virt_addr) { >> + dev_err(&hba->pdev->dev, >> + "Command Descriptor Memory allocation failed\n"); >> + goto ucd_fail; >> + } >> + >> + /* Align UCD to 128 bytes */ >> + hba->ucdl_virt_addr_aligned = >> + (void *) ALIGN((unsigned long) hba->ucdl_virt_addr, BYTES_128); >> + hba->ucdl_dma_addr_aligned = ALIGN(hba->ucdl_dma_addr, BYTES_128); >> + >> + /* >> + * Allocate memory for UTP Transfer descriptors. >> + * UFSHCI requires 1kb alignement of UTRD. So allocating >> + * extra 1024 bytes >> + */ >> + hba->utrdl_size = >> + (sizeof(struct utp_transfer_req_desc) * hba->nutrs) + BYTES_1024; >> + hba->utrdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev, >> + hba->utrdl_size, >> + &hba->utrdl_dma_addr, >> + GFP_KERNEL); >> + if (NULL == hba->utrdl_virt_addr) { >> + dev_err(&hba->pdev->dev, >> + "Transfer Descriptor Memory allocation failed\n"); >> + goto utrd_fail; >> + } >> + >> + /* alignement UTRD to 1kb */ >> + hba->utrdl_virt_addr_aligned = >> + (void *) ALIGN((unsigned long) hba->utrdl_virt_addr, BYTES_1024); >> + hba->utrdl_dma_addr_aligned = ALIGN(hba->utrdl_dma_addr, BYTES_1024); >> + >> + /* >> + * Allocate memory for UTP Task Management descriptors >> + * UFSHCI requires 1kb alignement of UTMRD. So allocating >> + * extra 1024 bytes >> + */ >> + hba->utmrdl_size = >> + sizeof(struct utp_task_req_desc) * hba->nutmrs + BYTES_1024; >> + hba->utmrdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev, >> + hba->utmrdl_size, >> + &hba->utmrdl_dma_addr, >> + GFP_KERNEL); >> + if (NULL == hba->utmrdl_virt_addr) { >> + dev_err(&hba->pdev->dev, >> + "Task Management Descriptor Memory allocation failed\n"); >> + goto utmrd_fail; >> + } >> + >> + /* alignement UTMRD to 1kb */ >> + hba->utmrdl_virt_addr_aligned = >> + (void *) ALIGN((unsigned long) hba->utmrdl_virt_addr, BYTES_1024); >> + hba->utmrdl_dma_addr_aligned = ALIGN(hba->utmrdl_dma_addr, BYTES_1024); >> + >> + /* Allocate memory for local reference block */ >> + hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL); >> + if (NULL == hba->lrb) { >> + dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n"); >> + goto lrb_fail; >> + } >> + >> + return 0; >> + >> +lrb_fail: >> + dma_free_coherent(&hba->pdev->dev, hba->utmrdl_size, >> + hba->utmrdl_virt_addr, hba->utmrdl_dma_addr); >> + hba->utmrdl_virt_addr = NULL; >> + hba->utmrdl_virt_addr_aligned = NULL; >> +utmrd_fail: >> + dma_free_coherent(&hba->pdev->dev, hba->utrdl_size, >> + hba->utrdl_virt_addr, hba->utrdl_dma_addr); >> + hba->utrdl_virt_addr = NULL; >> + hba->utrdl_virt_addr_aligned = NULL; >> +utrd_fail: >> + dma_free_coherent(&hba->pdev->dev, hba->ucdl_size, >> + hba->ucdl_virt_addr, hba->ucdl_dma_addr); >> + hba->ucdl_virt_addr = NULL; >> + hba->ucdl_virt_addr_aligned = NULL; >> +ucd_fail: >> + return -ENOMEM; >> +} >> + >> +/** >> + * ufshcd_host_memory_configure - configure local reference block with >> + * memory offsets >> + * @hba: per adapter instance >> + * >> + * Configure Host memory space >> + * 1) Update Corresponding UTRD.UCDBA and UTRD.UCDBAU with UCD DMA >> + * address. >> + * 2) Update each UTRD with Response UPIU offset, Response UPIU length >> + * and PRDT offset. >> + * 3) Save the corresponding addresses of UTRD, UCD.CMD, UCD.RSP and UCD.PRDT >> + * into local reference block. >> + */ >> +static void ufshcd_host_memory_configure(struct ufs_hba *hba) >> +{ >> + struct utp_transfer_cmd_desc *cmd_descp; >> + struct utp_transfer_req_desc *utrdlp; >> + dma_addr_t cmd_desc_dma_addr; >> + dma_addr_t cmd_desc_element_addr; >> + u16 response_offset; >> + u16 prdt_offset; >> + int cmd_desc_size; >> + int i; >> + >> + utrdlp = (struct utp_transfer_req_desc *)hba->utrdl_virt_addr_aligned; >> + cmd_descp = >> + (struct utp_transfer_cmd_desc *)hba->ucdl_virt_addr_aligned; >> + >> + response_offset = >> + offsetof(struct utp_transfer_cmd_desc, response_upiu); >> + prdt_offset = >> + offsetof(struct utp_transfer_cmd_desc, prd_table); >> + >> + cmd_desc_size = sizeof(struct utp_transfer_cmd_desc); >> + cmd_desc_dma_addr = hba->ucdl_dma_addr_aligned; >> + >> + for (i = 0; i < hba->nutrs; i++) { >> + /* Configure UTRD with command descriptor base address */ >> + cmd_desc_element_addr = >> + (cmd_desc_dma_addr + (cmd_desc_size * i)); >> + utrdlp[i].command_desc_base_addr_lo = >> + cpu_to_le32(cmd_desc_element_addr); >> + utrdlp[i].command_desc_base_addr_hi = >> + cpu_to_le32(cmd_desc_element_addr >> 32); >> + >> + /* Response upiu and prdt offset should be in double words */ >> + utrdlp[i].response_upiu_offset = >> + cpu_to_le16(BYTES_TO_DWORDS(response_offset)); >> + utrdlp[i].prd_table_offset = >> + cpu_to_le16(BYTES_TO_DWORDS(prdt_offset)); >> + utrdlp[i].response_upiu_length = >> + cpu_to_le16(ALIGNED_UPIU_SIZE); >> + >> + hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); >> + hba->lrb[i].ucd_cmd_ptr = >> + (struct utp_upiu_cmd *)(cmd_descp + i); >> + hba->lrb[i].ucd_rsp_ptr = >> + (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; >> + hba->lrb[i].ucd_prdt_ptr = >> + (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; >> + } >> +} >> + >> +/** >> + * ufshcd_dme_link_startup - Notify Unipro to perform link startup >> + * @hba: per adapter instance >> + * >> + * UIC_CMD_DME_LINK_STARTUP command must be issued to Unipro layer, >> + * in order to intitialize the Unipro link startup procedure. >> + * Once the Unipro links are up, the device connected to the controller >> + * is detected. >> + * >> + * Returns 0 on success, non-zero value on failure >> + */ >> +static int ufshcd_dme_link_startup(struct ufs_hba *hba) >> +{ >> + struct uic_command *uic_cmd; >> + unsigned long flags; >> + >> + /* check if controller is ready to accept UIC commands */ >> + if (((readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_STATUS)) & >> + UIC_COMMAND_READY) == 0x0) { >> + dev_err(&hba->pdev->dev, >> + "Controller not ready" >> + " to accept UIC commands\n"); >> + return -EINVAL; >> + } >> + >> + spin_lock_irqsave(hba->host->host_lock, flags); >> + uic_cmd = &hba->active_uic_cmd; >> + uic_cmd->command = UIC_CMD_DME_LINK_STARTUP; >> + uic_cmd->argument1 = 0; >> + uic_cmd->argument2 = 0; >> + uic_cmd->argument3 = 0; >> + >> + /* Enable UIC related interrupts */ >> + hba->int_enable_mask |= UIC_COMMAND_COMPL; >> + ufshcd_int_config(hba, UFSHCD_INT_ENABLE); >> + >> + /* sending UIC commands to controller */ >> + ufshcd_send_uic_command(hba, uic_cmd); >> + spin_unlock_irqrestore(hba->host->host_lock, flags); >> + >> + return 0; >> +} >> + >> +/** >> + * ufshcd_make_hba_operational - Make UFS controller operatinal >> + * @hba: per adapter instance >> + * >> + * To bring UFS host controller to operational state, >> + * 1. Check if device is present >> + * 2. Configure run-stop-registers >> + * 3. Enable required interrupts >> + * 4. Configure interrupt aggregation >> + * >> + * Returns 0 on success, non-zero value on failure >> + */ >> +static int ufshcd_make_hba_operational(struct ufs_hba *hba) >> +{ >> + u32 reg; >> + >> + /* check if device present */ >> + reg = readl((UFSHCD_MMIO_BASE + REG_CONTROLLER_STATUS)); >> + if (ufshcd_is_device_present(reg)) { >> + dev_err(&hba->pdev->dev, "cc: Device not present\n"); >> + return -EINVAL; >> + } >> + >> + /* >> + * UCRDY, UTMRLDY and UTRLRDY bits must be 1 >> + * DEI, HEI bits must be 0 >> + */ >> + if (!(ufshcd_get_lists_status(reg))) { >> + writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT, >> + (UFSHCD_MMIO_BASE + >> + REG_UTP_TASK_REQ_LIST_RUN_STOP)); >> + writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT, >> + (UFSHCD_MMIO_BASE + >> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)); >> + } else { >> + dev_err(&hba->pdev->dev, >> + "Host controller not ready to process requests"); >> + return -EINVAL; >> + } >> + >> + /* Enable required interrupts */ >> + hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL | >> + UIC_ERROR | >> + UTP_TASK_REQ_COMPL | >> + DEVICE_FATAL_ERROR | >> + CONTROLLER_FATAL_ERROR | >> + SYSTEM_BUS_FATAL_ERROR); >> + ufshcd_int_config(hba, UFSHCD_INT_ENABLE); > > UFS host controller specification Section 7.2.1, step 11, mentions > that the aggregation control register should be set if run/stop bit is > not enabled. > But In this case the run/ stop bit is set above before configuring the > aggregation register. Please check for the same in other places from > where it is called. > The spec mentions, (Section 7.2.1, step 11) "UTRIACR initialization may be executed at any time when the Run/Stop register (UTRLRSR) is not enabled or when no requests are outstanding." At this point in the code, during execution, there will not be any outstanding requests. >> + >> + /* Configure interrupt aggregation */ >> + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG); >> + >> + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; >> + >> + return 0; >> +} >> + >> +/** >> + * ufshcd_controller_enable - initialize the controller >> + * @hba: per adapter instance >> + * >> + * The controller resets its self and controller firmware start of day is >> + * kickes off. When controller is ready it will set the Host Controller >> + * Status bit to 1. >> + * >> + * Returns 0 on success, non-zero value on failure >> + */ >> +static int ufshcd_controller_enable(struct ufs_hba *hba) >> +{ >> + int retry; >> + >> + /* >> + * msleep of 1 and 5 used in this function might result in msleep(20), >> + * but it was necessary to send the UFS FPGA to reset mode during >> + * development and testing of this driver. msleep can be changed to >> + * mdelay and retry count can be reduced based on the controller. >> + */ >> + >> + /* change controller state to "reset state" */ >> + writel(0, (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE)); >> + msleep(5); >> + >> + writel(CONTROLLER_ENABLE, >> + (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE)); >> + msleep(1); >> + >> + /* wait for the host controller to complete initialization */ >> + retry = 10; >> + while (((readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE)) & >> + CONTROLLER_ENABLE) != 0x1) { >> + if (retry) { >> + retry--; >> + } else { >> + dev_err(&hba->pdev->dev, >> + "Controller enable failed\n"); >> + return -EINVAL; >> + } >> + msleep(5); >> + } >> + return 0; >> +} >> + >> +/** >> + * ufshcd_initialize_hba - start the initialization process >> + * @hba: per adapter instance >> + * >> + * Initialize the Controller >> + * 1) Enable the controller via ufshcd_controller_enable. >> + * 2) Program the Transfer Request List Address with the starting address of >> + * UTRDL. >> + * >> + * 3) Program the Task Management Request List Address with starting address >> + * of UTMRDL. >> + * >> + * Returns 0 on success, non-zero value on failure. >> + */ >> +static int ufshcd_initialize_hba(struct ufs_hba *hba) >> +{ >> + if (ufshcd_controller_enable(hba)) >> + return -1; >> + >> + /* Configure TR/TM address registers */ >> + writel(hba->utrdl_dma_addr_aligned, >> + (UFSHCD_MMIO_BASE + REG_UTP_TRANSFER_REQ_LIST_BASE_L)); >> + writel((hba->utrdl_dma_addr_aligned >> 32), >> + (UFSHCD_MMIO_BASE + REG_UTP_TRANSFER_REQ_LIST_BASE_H)); >> + writel(hba->utmrdl_dma_addr_aligned, >> + (UFSHCD_MMIO_BASE + REG_UTP_TASK_REQ_LIST_BASE_L)); >> + writel((hba->utmrdl_dma_addr_aligned >> 32), >> + (UFSHCD_MMIO_BASE + REG_UTP_TASK_REQ_LIST_BASE_H)); >> + >> + /* Initialize unipro link startup procedure */ >> + return ufshcd_dme_link_startup(hba); >> +} >> + >> +/** >> + * ufshcd_uic_cc_handler - handle UIC command completion >> + * @work: pointer to a work queue structure >> + * >> + * Returns 0 on success, non-zero value on failure >> + */ >> +static void ufshcd_uic_cc_handler (struct work_struct *work) >> +{ >> + struct ufs_hba *hba; >> + >> + hba = container_of(work, struct ufs_hba, uic_workq); >> + >> + if ((UIC_CMD_DME_LINK_STARTUP == hba->active_uic_cmd.command) && >> + !(ufshcd_get_uic_cmd_result(hba))) { >> + >> + if (ufshcd_make_hba_operational(hba)) >> + dev_err(&hba->pdev->dev, >> + "cc: hba not operational state\n"); >> + return; >> + } >> +} >> + >> +/** >> + * ufshcd_sl_intr - Interrupt service routine >> + * @hba: per adapter instance >> + * @intr_status: contains interrupts generated by the controller >> + */ >> +static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) >> +{ >> + if (intr_status & UIC_COMMAND_COMPL) >> + schedule_work(&hba->uic_workq); >> +} >> + >> +/** >> + * ufshcd_intr - Main interrupt service routine >> + * @irq: irq number >> + * @__hba: pointer to adapter instance >> + * >> + * Returns IRQ_HANDLED - If interrupt is valid >> + * IRQ_NONE - If invalid interrupt >> + */ >> +static irqreturn_t ufshcd_intr(int irq, void *__hba) >> +{ >> + unsigned long flags; >> + u32 intr_status; >> + irqreturn_t retval = IRQ_NONE; >> + struct ufs_hba *hba = __hba; >> + >> + spin_lock_irqsave(hba->host->host_lock, flags); >> + intr_status = readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS); >> + >> + if (intr_status) { >> + ufshcd_sl_intr(hba, intr_status); >> + >> + /* If UFSHCI 1.0 then clear interrupt status register */ >> + if (UFSHCI_VERSION_10 == hba->ufs_version) >> + writel(intr_status, >> + (UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS)); >> + retval = IRQ_HANDLED; >> + } >> + spin_unlock_irqrestore(hba->host->host_lock, flags); >> + return retval; >> +} >> + >> +static struct scsi_host_template ufshcd_driver_template = { >> + .module = THIS_MODULE, >> + .name = UFSHCD, >> + .proc_name = UFSHCD, >> + .this_id = -1, >> +}; >> + >> +/** >> + * ufshcd_shutdown - main funciton to put the controller in reset state >> + * @pdev: pointer to PCI device handle >> + */ >> +static void ufshcd_shutdown(struct pci_dev *pdev) >> +{ >> + ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev)); >> +} >> + >> +#ifdef CONFIG_PM >> +/** >> + * ufshcd_suspend - suspend power management function >> + * @pdev: pointer to PCI device handle >> + * @state: power state >> + * >> + * Returns -ENOSYS >> + */ >> +static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state) >> +{ >> + return -ENOSYS; >> +} >> + >> +/** >> + * ufshcd_resume - resume power management function >> + * @pdev: pointer to PCI device handle >> + * >> + * Returns -ENOSYS >> + */ >> +static int ufshcd_resume(struct pci_dev *pdev) >> +{ >> + return -ENOSYS; >> +} >> +#endif /* CONFIG_PM */ >> + >> +/** >> + * ufshcd_hba_free - free allocated memory for >> + * host memory space data structures >> + * @hba: per adapter instance >> + */ >> +static void ufshcd_hba_free(struct ufs_hba *hba) >> +{ >> + iounmap(UFSHCD_MMIO_BASE); >> + ufshcd_free_hba_memory(hba); >> + pci_release_regions(hba->pdev); >> +} >> + >> +/** >> + * ufshcd_remove - deallocate PCI/SCSI host and host memory space >> + * data structure memory >> + * @pdev - pointer to PCI handle >> + */ >> +static void ufshcd_remove(struct pci_dev *pdev) >> +{ >> + struct ufs_hba *hba = pci_get_drvdata(pdev); >> + >> + /* disable interrupts */ >> + ufshcd_int_config(hba, UFSHCD_INT_DISABLE); >> + free_irq(pdev->irq, hba); >> + >> + ufshcd_hba_stop(hba); >> + ufshcd_hba_free(hba); >> + >> + scsi_remove_host(hba->host); >> + scsi_host_put(hba->host); >> + pci_set_drvdata(pdev, NULL); >> + pci_clear_master(pdev); >> + pci_disable_device(pdev); >> +} >> + >> +/** >> + * ufshcd_set_dma_mask - Set dma addressing >> + * @pdev: PCI device struct >> + * >> + * Returns 0 for success, non-zero for failure >> + */ >> +static int ufshcd_set_dma_mask(struct pci_dev *pdev) >> +{ >> + int err; >> + >> + do { >> + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); >> + if (!err) { >> + err = pci_set_consistent_dma_mask(pdev, >> + DMA_BIT_MASK(64)); >> + break; >> + } >> + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); >> + if (!err) >> + err = pci_set_consistent_dma_mask(pdev, >> + DMA_BIT_MASK(32)); >> + } while (0); >> + >> + return err; >> +} >> + >> +/** >> + * ufshcd_probe - probe routine of the driver >> + * @pdev: pointer to PCI device handle >> + * @id: PCI device id >> + * >> + * Returns 0 on success, non-zero value on failure >> + */ >> +static int __devinit >> +ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id) >> +{ >> + struct Scsi_Host *host; >> + struct ufs_hba *hba; >> + int ufs_hba_len; >> + int err; >> + >> + ufs_hba_len = sizeof(struct ufs_hba); >> + err = pci_enable_device(pdev); >> + if (err) { >> + dev_err(&pdev->dev, "pci_enable_device failed\n"); >> + goto out_error; >> + } >> + >> + pci_set_master(pdev); >> + >> + host = scsi_host_alloc(&ufshcd_driver_template, ufs_hba_len); >> + if (!host) { >> + dev_err(&pdev->dev, "scsi_host_alloc failed\n"); >> + err = -ENOMEM; >> + goto out_disable; >> + } >> + hba = (struct ufs_hba *)host->hostdata; >> + >> + err = pci_request_regions(pdev, UFSHCD); >> + if (err < 0) { >> + dev_err(&pdev->dev, "request regions failed\n"); >> + goto out_disable; >> + } >> + >> + hba->mmio_base = pci_ioremap_bar(pdev, 0); >> + if (!hba->mmio_base) { >> + dev_err(&pdev->dev, "memory map failed\n"); >> + err = -ENOMEM; >> + goto out_release_regions; >> + } >> + >> + err = ufshcd_set_dma_mask(pdev); >> + if (err) { >> + dev_err(&pdev->dev, "set dma mask failed\n"); >> + goto out_iounmap; >> + } >> + >> + hba->host = host; >> + hba->pdev = pdev; >> + >> + /* Read capabilities registers */ >> + ufshcd_hba_capabilities(hba); >> + >> + /* Get UFS version supported by the controller */ >> + hba->ufs_version = ufshcd_get_ufs_version(hba); >> + >> + /* Allocate memory for host memory space */ >> + err = ufshcd_memory_alloc(hba); >> + if (err) { >> + dev_err(&pdev->dev, "Memory allocation failed\n"); >> + goto out_iounmap; >> + } >> + >> + /* Configure LRB */ >> + ufshcd_host_memory_configure(hba); >> + >> + host->can_queue = hba->nutrs; >> + host->max_id = UFSHCD_MAX_ID; >> + host->max_lun = UFSHCD_MAX_LUNS; >> + host->max_channel = UFSHCD_MAX_CHANNEL; >> + host->unique_id = host->host_no; >> + >> + /* Initialize work queues */ >> + INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler); >> + >> + /* IRQ registration */ >> + err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba); >> + if (err) { >> + dev_err(&pdev->dev, "request irq failed\n"); >> + goto out_lrb_free; >> + } >> + >> + pci_set_drvdata(pdev, hba); >> + >> + err = scsi_add_host(host, &pdev->dev); >> + if (err) { >> + dev_err(&pdev->dev, "scsi_add_host failed\n"); >> + goto out_free_irq; >> + } >> + >> + /* Initialization routine */ >> + err = ufshcd_initialize_hba(hba); >> + if (err) { >> + dev_err(&pdev->dev, "Initialization failed\n"); >> + goto out_free_irq; >> + } >> + >> + return 0; >> + >> +out_free_irq: >> + free_irq(pdev->irq, hba); >> +out_lrb_free: >> + ufshcd_free_hba_memory(hba); >> +out_iounmap: >> + iounmap(hba->mmio_base); >> +out_release_regions: >> + pci_release_regions(pdev); >> +out_disable: >> + scsi_host_put(host); >> + pci_clear_master(pdev); >> + pci_disable_device(pdev); >> +out_error: >> + return err; >> +} >> + >> +static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = { >> + { 0x144D, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, >> + { } /* terminate list */ >> +}; >> + >> +MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl); >> + >> +static struct pci_driver ufshcd_pci_driver = { >> + .name = UFSHCD, >> + .id_table = ufshcd_pci_tbl, >> + .probe = ufshcd_probe, >> + .remove = __devexit_p(ufshcd_remove), >> + .shutdown = ufshcd_shutdown, >> +#ifdef CONFIG_PM >> + .suspend = ufshcd_suspend, >> + .resume = ufshcd_resume, >> +#endif >> +}; >> + >> +/** >> + * ufshcd_init - Driver registration routine >> + */ >> +static int __init ufshcd_init(void) >> +{ >> + return pci_register_driver(&ufshcd_pci_driver); >> +} >> +module_init(ufshcd_init); >> + >> +/** >> + * ufshcd_exit - Driver exit clean-up routine >> + */ >> +static void __exit ufshcd_exit(void) >> +{ >> + pci_unregister_driver(&ufshcd_pci_driver); >> +} >> +module_exit(ufshcd_exit); >> + >> + >> +MODULE_AUTHOR("Santosh Yaragnavi, Vinayak Holikatti"); >> +MODULE_DESCRIPTION("Generic UFS host controller driver"); >> +MODULE_LICENSE("GPL"); >> +MODULE_VERSION(UFSHCD_DRIVER_VERSION); >> diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h >> new file mode 100644 >> index 0000000..f8701b7 >> --- /dev/null >> +++ b/drivers/scsi/ufs/ufshci.h >> @@ -0,0 +1,360 @@ >> +/* >> + * Universal Flash Storage Host controller driver >> + * >> + * This code is based on drivers/scsi/ufs/ufshci.h >> + * Copyright (C) 2011-2012 Samsung India Software Operations >> + * >> + * Santosh Yaraganavi <santosh.sy@xxxxxxxxxxx> >> + * Vinayak Holikatti <h.vinayak@xxxxxxxxxxx> >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * as published by the Free Software Foundation; either version 2 >> + * of the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * NO WARRANTY >> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR >> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT >> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, >> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is >> + * solely responsible for determining the appropriateness of using and >> + * distributing the Program and assumes all risks associated with its >> + * exercise of rights under this Agreement, including but not limited to >> + * the risks and costs of program errors, damage to or loss of data, >> + * programs or equipment, and unavailability or interruption of operations. >> + >> + * DISCLAIMER OF LIABILITY >> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY >> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND >> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED >> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES >> + >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, >> + * USA. >> + */ >> + >> +#ifndef _UFSHCI_H >> +#define _UFSHCI_H >> + >> +/* UFSHCI Registers */ >> +enum { >> + REG_CONTROLLER_CAPABILITIES = 0x00, >> + REG_UFS_VERSION = 0x08, >> + REG_CONTROLLER_DEV_ID = 0x10, >> + REG_CONTROLLER_PROD_ID = 0x14, >> + REG_INTERRUPT_STATUS = 0x20, >> + REG_INTERRUPT_ENABLE = 0x24, >> + REG_CONTROLLER_STATUS = 0x30, >> + REG_CONTROLLER_ENABLE = 0x34, >> + REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER = 0x38, >> + REG_UIC_ERROR_CODE_DATA_LINK_LAYER = 0x3C, >> + REG_UIC_ERROR_CODE_NETWORK_LAYER = 0x40, >> + REG_UIC_ERROR_CODE_TRANSPORT_LAYER = 0x44, >> + REG_UIC_ERROR_CODE_DME = 0x48, >> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL = 0x4C, >> + REG_UTP_TRANSFER_REQ_LIST_BASE_L = 0x50, >> + REG_UTP_TRANSFER_REQ_LIST_BASE_H = 0x54, >> + REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58, >> + REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C, >> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60, >> + REG_UTP_TASK_REQ_LIST_BASE_L = 0x70, >> + REG_UTP_TASK_REQ_LIST_BASE_H = 0x74, >> + REG_UTP_TASK_REQ_DOOR_BELL = 0x78, >> + REG_UTP_TASK_REQ_LIST_CLEAR = 0x7C, >> + REG_UTP_TASK_REQ_LIST_RUN_STOP = 0x80, >> + REG_UIC_COMMAND = 0x90, >> + REG_UIC_COMMAND_ARG_1 = 0x94, >> + REG_UIC_COMMAND_ARG_2 = 0x98, >> + REG_UIC_COMMAND_ARG_3 = 0x9C >> +}; >> + >> +/* Controller capability masks */ >> +enum { >> + MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F, >> + MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000, >> + MASK_64_ADDRESSING_SUPPORT = 0x01000000, >> + MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000, >> + MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000 >> +}; >> + >> +/* UFS Version 08h */ >> +#define MINOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 0) >> +#define MAJOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 16) >> + >> +/* Controller UFSHCI version */ >> +enum { >> + UFSHCI_VERSION_10 = 0x00010000, >> + UFSHCI_VERSION_11 = 0x00010100 >> +}; >> + >> +/* >> + * HCDDID - Host Controller Identification Descriptor >> + * - Device ID and Device Class 10h >> + */ >> +#define DEVICE_CLASS UFS_MASK(0xFFFF, 0) >> +#define DEVICE_ID UFS_MASK(0xFF, 24) >> + >> +/* >> + * HCPMID - Host Controller Identification Descriptor >> + * - Product/Manufacturer ID 14h >> + */ >> +#define MANUFACTURE_ID_MASK UFS_MASK(0xFFFF, 0) >> +#define PRODUCT_ID_MASK UFS_MASK(0xFFFF, 16) >> + >> +#define UFS_BIT(x) (1L << (x)) >> + >> +#define UTP_TRANSFER_REQ_COMPL UFS_BIT(0) >> +#define UIC_DME_END_PT_RESET UFS_BIT(1) >> +#define UIC_ERROR UFS_BIT(2) >> +#define UIC_TEST_MODE UFS_BIT(3) >> +#define UIC_POWER_MODE UFS_BIT(4) >> +#define UIC_HIBERNATE_EXIT UFS_BIT(5) >> +#define UIC_HIBERNATE_ENTER UFS_BIT(6) >> +#define UIC_LINK_LOST UFS_BIT(7) >> +#define UIC_LINK_STARTUP UFS_BIT(8) >> +#define UTP_TASK_REQ_COMPL UFS_BIT(9) >> +#define UIC_COMMAND_COMPL UFS_BIT(10) >> +#define DEVICE_FATAL_ERROR UFS_BIT(11) >> +#define CONTROLLER_FATAL_ERROR UFS_BIT(16) >> +#define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17) >> + >> +#define UFSHCD_ERROR_MASK (UIC_ERROR |\ >> + DEVICE_FATAL_ERROR |\ >> + CONTROLLER_FATAL_ERROR |\ >> + SYSTEM_BUS_FATAL_ERROR) >> + >> +#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\ >> + CONTROLLER_FATAL_ERROR |\ >> + SYSTEM_BUS_FATAL_ERROR) >> + >> +/* HCS - Host Controller Status 30h */ >> +#define DEVICE_PRESENT UFS_BIT(0) >> +#define UTP_TRANSFER_REQ_LIST_READY UFS_BIT(1) >> +#define UTP_TASK_REQ_LIST_READY UFS_BIT(2) >> +#define UIC_COMMAND_READY UFS_BIT(3) >> +#define HOST_ERROR_INDICATOR UFS_BIT(4) >> +#define DEVICE_ERROR_INDICATOR UFS_BIT(5) >> +#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8) >> + >> +/* HCE - Host Controller Enable 34h */ >> +#define CONTROLLER_ENABLE UFS_BIT(0) >> + >> +/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ >> +#define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31) >> +#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F >> + >> +/* UECDL - Host UIC Error Code Data Link Layer 3Ch */ >> +#define UIC_DATA_LINK_LAYER_ERROR UFS_BIT(31) >> +#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0x7FFF >> +#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT 0x2000 >> + >> +/* UECN - Host UIC Error Code Network Layer 40h */ >> +#define UIC_NETWORK_LAYER_ERROR UFS_BIT(31) >> +#define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7 >> + >> +/* UECT - Host UIC Error Code Transport Layer 44h */ >> +#define UIC_TRANSPORT_LAYER_ERROR UFS_BIT(31) >> +#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F >> + >> +/* UECDME - Host UIC Error Code DME 48h */ >> +#define UIC_DME_ERROR UFS_BIT(31) >> +#define UIC_DME_ERROR_CODE_MASK 0x1 >> + >> +#define INT_AGGR_TIMEOUT_VAL_MASK 0xFF >> +#define INT_AGGR_COUNTER_THRESHOLD_MASK UFS_MASK(0x1F, 8) >> +#define INT_AGGR_COUNTER_AND_TIMER_RESET UFS_BIT(16) >> +#define INT_AGGR_STATUS_BIT UFS_BIT(20) >> +#define INT_AGGR_PARAM_WRITE UFS_BIT(24) >> +#define INT_AGGR_ENABLE UFS_BIT(31) >> + >> +/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */ >> +#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT UFS_BIT(0) >> + >> +/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */ >> +#define UTP_TASK_REQ_LIST_RUN_STOP_BIT UFS_BIT(0) >> + >> +/* UICCMD - UIC Command */ >> +#define COMMAND_OPCODE_MASK 0xFF >> +#define GEN_SELECTOR_INDEX_MASK 0xFFFF >> + >> +#define MIB_ATTRIBUTE_MASK UFS_MASK(0xFFFF, 16) >> +#define RESET_LEVEL 0xFF >> + >> +#define ATTR_SET_TYPE_MASK UFS_MASK(0xFF, 16) >> +#define CONFIG_RESULT_CODE_MASK 0xFF >> +#define GENERIC_ERROR_CODE_MASK 0xFF >> + >> +/* UIC Commands */ >> +enum { >> + UIC_CMD_DME_GET = 0x01, >> + UIC_CMD_DME_SET = 0x02, >> + UIC_CMD_DME_PEER_GET = 0x03, >> + UIC_CMD_DME_PEER_SET = 0x04, >> + UIC_CMD_DME_POWERON = 0x10, >> + UIC_CMD_DME_POWEROFF = 0x11, >> + UIC_CMD_DME_ENABLE = 0x12, >> + UIC_CMD_DME_RESET = 0x14, >> + UIC_CMD_DME_END_PT_RST = 0x15, >> + UIC_CMD_DME_LINK_STARTUP = 0x16, >> + UIC_CMD_DME_HIBER_ENTER = 0x17, >> + UIC_CMD_DME_HIBER_EXIT = 0x18, >> + UIC_CMD_DME_TEST_MODE = 0x1A >> +}; >> + >> +/* UIC Config result code / Generic error code */ >> +enum { >> + UIC_CMD_RESULT_SUCCESS = 0x00, >> + UIC_CMD_RESULT_INVALID_ATTR = 0x01, >> + UIC_CMD_RESULT_FAILURE = 0x01, >> + UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02, >> + UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03, >> + UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04, >> + UIC_CMD_RESULT_BAD_INDEX = 0x05, >> + UIC_CMD_RESULT_LOCKED_ATTR = 0x06, >> + UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07, >> + UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08, >> + UIC_CMD_RESULT_BUSY = 0x09, >> + UIC_CMD_RESULT_DME_FAILURE = 0x0A >> +}; >> + >> +#define MASK_UIC_COMMAND_RESULT 0xFF >> + >> +#define INT_AGGR_COUNTER_THRESHOLD_VALUE (0x1F << 8) >> +#define INT_AGGR_TIMEOUT_VALUE (0x02) >> + >> +/* >> + * Request Descriptor Definitions >> + */ >> + >> +/* Transfer request command type */ >> +enum { >> + UTP_CMD_TYPE_SCSI = 0x0, >> + UTP_CMD_TYPE_UFS = 0x1, >> + UTP_CMD_TYPE_DEV_MANAGE = 0x2 >> +}; >> + >> +enum { >> + UTP_SCSI_COMMAND = 0x00000000, >> + UTP_NATIVE_UFS_COMMAND = 0x10000000, >> + UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000, >> + UTP_REQ_DESC_INT_CMD = 0x01000000 >> +}; >> + >> +/* UTP Transfer Request Data Direction (DD) */ >> +enum { >> + UTP_NO_DATA_TRANSFER = 0x00000000, >> + UTP_HOST_TO_DEVICE = 0x02000000, >> + UTP_DEVICE_TO_HOST = 0x04000000 >> +}; >> + >> +/* Overall command status values */ >> +enum { >> + OCS_SUCCESS = 0x0, >> + OCS_INVALID_CMD_TABLE_ATTR = 0x1, >> + OCS_INVALID_PRDT_ATTR = 0x2, >> + OCS_MISMATCH_DATA_BUF_SIZE = 0x3, >> + OCS_MISMATCH_RESP_UPIU_SIZE = 0x4, >> + OCS_PEER_COMM_FAILURE = 0x5, >> + OCS_ABORTED = 0x6, >> + OCS_FATAL_ERROR = 0x7, >> + OCS_INVALID_COMMAND_STATUS = 0x0F, >> + MASK_OCS = 0x0F >> +}; >> + >> +/** >> + * struct ufshcd_sg_entry - UFSHCI PRD Entry >> + * @base_addr: Lower 32bit physical address DW-0 >> + * @upper_addr: Upper 32bit physical address DW-1 >> + * @reserved: Reserved for future use DW-2 >> + * @size: size of physical segment DW-3 >> + */ >> +struct ufshcd_sg_entry { >> + u32 base_addr; >> + u32 upper_addr; >> + u32 reserved; >> + u32 size; >> +}; >> + >> +/** >> + * struct utp_transfer_cmd_desc - UFS Commad Descriptor structure >> + * @command_upiu: Command UPIU Frame address >> + * @response_upiu: Response UPIU Frame address >> + * @prd_table: Physcial Region Descriptor >> + */ >> +struct utp_transfer_cmd_desc { >> + u8 command_upiu[ALIGNED_UPIU_SIZE]; >> + u8 response_upiu[ALIGNED_UPIU_SIZE]; >> + struct ufshcd_sg_entry prd_table[SG_ALL]; >> +}; >> + >> +/** >> + * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD >> + * @dword0: Descriptor Header DW0 >> + * @dword1: Descriptor Header DW1 >> + * @dword2: Descriptor Header DW2 >> + * @dword3: Descriptor Header DW3 >> + */ >> +struct request_desc_header { >> + u32 dword_0; >> + u32 dword_1; >> + u32 dword_2; >> + u32 dword_3; >> +}; >> + >> +/** >> + * struct utp_transfer_req_desc - UTRD structure >> + * @header: UTRD header DW-0 to DW-3 >> + * @command_desc_base_addr_lo: UCD base address low DW-4 >> + * @command_desc_base_addr_hi: UCD base address high DW-5 >> + * @response_upiu_length: response UPIU length DW-6 >> + * @response_upiu_offset: response UPIU offset DW-6 >> + * @prd_table_length: Physical region descriptor length DW-7 >> + * @prd_table_offset: Physical region descriptor offset DW-7 >> + */ >> +struct utp_transfer_req_desc { >> + >> + /* DW 0-3 */ >> + struct request_desc_header header; >> + >> + /* DW 4-5*/ >> + u32 command_desc_base_addr_lo; >> + u32 command_desc_base_addr_hi; >> + >> + /* DW 6 */ >> + u16 response_upiu_length; >> + u16 response_upiu_offset; >> + >> + /* DW 7 */ >> + u16 prd_table_length; >> + u16 prd_table_offset; >> +}; >> + >> +/** >> + * struct utp_task_req_desc - UTMRD structure >> + * @header: UTMRD header DW-0 to DW-3 >> + * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11 >> + * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19 >> + */ >> +struct utp_task_req_desc { >> + >> + /* DW 0-3 */ >> + struct request_desc_header header; >> + >> + /* DW 4-11 */ >> + u32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS]; >> + >> + /* DW 12-19 */ >> + u32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS]; >> +}; >> + >> +#endif /* End of Header */ >> -- >> 1.7.5.4 >> -- ~Santosh -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html