Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758383Ab2BJHHJ (ORCPT ); Fri, 10 Feb 2012 02:07:09 -0500 Received: from mail-ee0-f46.google.com ([74.125.83.46]:53850 "EHLO mail-ee0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753881Ab2BJHHG convert rfc822-to-8bit (ORCPT ); Fri, 10 Feb 2012 02:07:06 -0500 MIME-Version: 1.0 In-Reply-To: References: <1328158649-4137-1-git-send-email-vinholikatti@gmail.com> <1328158649-4137-2-git-send-email-vinholikatti@gmail.com> From: Santosh Y Date: Fri, 10 Feb 2012 12:36:43 +0530 Message-ID: Subject: Re: [PATCH 1/4] [SCSI] ufshcd: UFS Host controller driver To: Girish K S Cc: Vinayak Holikatti , James.Bottomley@hansenpartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, patches@linaro.org, linux-samsung-soc@vger.kernel.org, saugata.das@linaro.org, arnd@arndb.de, venkat@linaro.org, vishak.g@samsung.com, k.rajesh@samsung.com, yejin.moon@samsung.com, Sree kumar Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 69029 Lines: 1830 On Fri, Feb 10, 2012 at 12:45 AM, Girish K S wrote: > On 2 February 2012 10:27, Vinayak Holikatti wrote: >> From: Santosh Yaraganavi >> >> 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 >> Signed-off-by: Vinayak Holikatti >> Reviewed-by: Arnd Bergmann >> Reviewed-by: Saugata Das >> Reviewed-by: Vishak G >> Reviewed-by: Girish K S >> --- >> ?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 >> +# Vinayak Holikatti >> + >> +# 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 >> + * Vinayak Holikatti >> + * >> + * 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 >> + * Vinayak Holikatti >> + * >> + * 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 >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#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 >> + * Vinayak Holikatti >> + * >> + * 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-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/