diff options
author | Vinayak Holikatti <vinholikatti@gmail.com> | 2013-02-25 11:14:33 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-02-25 11:56:32 -0500 |
commit | e0eca63e342124cff4307eafb43908cab5b3cf88 (patch) | |
tree | 3e5c881c16ba56157905fdc492029a7ad2ddfbcc /drivers/scsi/ufs | |
parent | 3b1d05807a9a68c6d0580e9248247a774a4d3be6 (diff) |
[SCSI] ufs: Separate PCI code into glue driver
This patch separates PCI code from ufshcd.c and makes it as a
core driver module and adds a new file ufshcd-pci.c as PCI glue
driver.
[jejb: strip __devinit and devexit_p()]
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Namjae Jeon <linkinjeon@gmail.com>
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
Tested-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Vinayak Holikatti <vinholikatti@gmail.com>
Signed-off-by: Santosh Yaraganavi <santoshsy@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r-- | drivers/scsi/ufs/Kconfig | 26 | ||||
-rw-r--r-- | drivers/scsi/ufs/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd-pci.c | 211 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 327 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 202 |
5 files changed, 440 insertions, 327 deletions
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 8ee40dff3dfb..0371047c5922 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig | |||
@@ -33,7 +33,27 @@ | |||
33 | # this program. | 33 | # this program. |
34 | 34 | ||
35 | config SCSI_UFSHCD | 35 | config SCSI_UFSHCD |
36 | tristate "Universal Flash Storage host controller driver" | 36 | tristate "Universal Flash Storage Controller Driver Core" |
37 | depends on PCI && SCSI | 37 | depends on SCSI |
38 | ---help--- | 38 | ---help--- |
39 | This is a generic driver which supports PCIe UFS Host controllers. | 39 | This selects the support for UFS devices in Linux, say Y and make |
40 | sure that you know the name of your UFS host adapter (the card | ||
41 | inside your computer that "speaks" the UFS protocol, also | ||
42 | called UFS Host Controller), because you will be asked for it. | ||
43 | The module will be called ufshcd. | ||
44 | |||
45 | To compile this driver as a module, choose M here and read | ||
46 | <file:Documentation/scsi/ufs.txt>. | ||
47 | However, do not compile this as a module if your root file system | ||
48 | (the one containing the directory /) is located on a UFS device. | ||
49 | |||
50 | config SCSI_UFSHCD_PCI | ||
51 | tristate "PCI bus based UFS Controller support" | ||
52 | depends on SCSI_UFSHCD && PCI | ||
53 | ---help--- | ||
54 | This selects the PCI UFS Host Controller Interface. Select this if | ||
55 | you have UFS Host Controller with PCI Interface. | ||
56 | |||
57 | If you have a controller with this interface, say Y or M here. | ||
58 | |||
59 | If unsure, say N. | ||
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index adf7895a6a91..9eda0dfbd6df 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | # UFSHCD makefile | 1 | # UFSHCD makefile |
2 | obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o | 2 | obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o |
3 | obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o | ||
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c new file mode 100644 index 000000000000..5cb1d75f5868 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-pci.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Universal Flash Storage Host controller PCI glue driver | ||
3 | * | ||
4 | * This code is based on drivers/scsi/ufs/ufshcd-pci.c | ||
5 | * Copyright (C) 2011-2013 Samsung India Software Operations | ||
6 | * | ||
7 | * Authors: | ||
8 | * Santosh Yaraganavi <santosh.sy@samsung.com> | ||
9 | * Vinayak Holikatti <h.vinayak@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * See the COPYING file in the top-level directory or visit | ||
16 | * <http://www.gnu.org/licenses/gpl-2.0.html> | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * This program is provided "AS IS" and "WITH ALL FAULTS" and | ||
24 | * without warranty of any kind. You are solely responsible for | ||
25 | * determining the appropriateness of using and distributing | ||
26 | * the program and assume all risks associated with your exercise | ||
27 | * of rights with respect to the program, including but not limited | ||
28 | * to infringement of third party rights, the risks and costs of | ||
29 | * program errors, damage to or loss of data, programs or equipment, | ||
30 | * and unavailability or interruption of operations. Under no | ||
31 | * circumstances will the contributor of this Program be liable for | ||
32 | * any damages of any kind arising from your use or distribution of | ||
33 | * this program. | ||
34 | */ | ||
35 | |||
36 | #include "ufshcd.h" | ||
37 | #include <linux/pci.h> | ||
38 | |||
39 | #ifdef CONFIG_PM | ||
40 | /** | ||
41 | * ufshcd_pci_suspend - suspend power management function | ||
42 | * @pdev: pointer to PCI device handle | ||
43 | * @state: power state | ||
44 | * | ||
45 | * Returns -ENOSYS | ||
46 | */ | ||
47 | static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
48 | { | ||
49 | /* | ||
50 | * TODO: | ||
51 | * 1. Call ufshcd_suspend | ||
52 | * 2. Do bus specific power management | ||
53 | */ | ||
54 | |||
55 | return -ENOSYS; | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * ufshcd_pci_resume - resume power management function | ||
60 | * @pdev: pointer to PCI device handle | ||
61 | * | ||
62 | * Returns -ENOSYS | ||
63 | */ | ||
64 | static int ufshcd_pci_resume(struct pci_dev *pdev) | ||
65 | { | ||
66 | /* | ||
67 | * TODO: | ||
68 | * 1. Call ufshcd_resume. | ||
69 | * 2. Do bus specific wake up | ||
70 | */ | ||
71 | |||
72 | return -ENOSYS; | ||
73 | } | ||
74 | #endif /* CONFIG_PM */ | ||
75 | |||
76 | /** | ||
77 | * ufshcd_pci_shutdown - main function to put the controller in reset state | ||
78 | * @pdev: pointer to PCI device handle | ||
79 | */ | ||
80 | static void ufshcd_pci_shutdown(struct pci_dev *pdev) | ||
81 | { | ||
82 | ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev)); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space | ||
87 | * data structure memory | ||
88 | * @pdev - pointer to PCI handle | ||
89 | */ | ||
90 | static void ufshcd_pci_remove(struct pci_dev *pdev) | ||
91 | { | ||
92 | struct ufs_hba *hba = pci_get_drvdata(pdev); | ||
93 | |||
94 | disable_irq(pdev->irq); | ||
95 | free_irq(pdev->irq, hba); | ||
96 | ufshcd_remove(hba); | ||
97 | pci_release_regions(pdev); | ||
98 | pci_set_drvdata(pdev, NULL); | ||
99 | pci_clear_master(pdev); | ||
100 | pci_disable_device(pdev); | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * ufshcd_set_dma_mask - Set dma mask based on the controller | ||
105 | * addressing capability | ||
106 | * @pdev: PCI device structure | ||
107 | * | ||
108 | * Returns 0 for success, non-zero for failure | ||
109 | */ | ||
110 | static int ufshcd_set_dma_mask(struct pci_dev *pdev) | ||
111 | { | ||
112 | int err; | ||
113 | |||
114 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) | ||
115 | && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) | ||
116 | return 0; | ||
117 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
118 | if (!err) | ||
119 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
120 | return err; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * ufshcd_pci_probe - probe routine of the driver | ||
125 | * @pdev: pointer to PCI device handle | ||
126 | * @id: PCI device id | ||
127 | * | ||
128 | * Returns 0 on success, non-zero value on failure | ||
129 | */ | ||
130 | static int | ||
131 | ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
132 | { | ||
133 | struct ufs_hba *hba; | ||
134 | void __iomem *mmio_base; | ||
135 | int err; | ||
136 | |||
137 | err = pci_enable_device(pdev); | ||
138 | if (err) { | ||
139 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
140 | goto out_error; | ||
141 | } | ||
142 | |||
143 | pci_set_master(pdev); | ||
144 | |||
145 | |||
146 | err = pci_request_regions(pdev, UFSHCD); | ||
147 | if (err < 0) { | ||
148 | dev_err(&pdev->dev, "request regions failed\n"); | ||
149 | goto out_disable; | ||
150 | } | ||
151 | |||
152 | mmio_base = pci_ioremap_bar(pdev, 0); | ||
153 | if (!mmio_base) { | ||
154 | dev_err(&pdev->dev, "memory map failed\n"); | ||
155 | err = -ENOMEM; | ||
156 | goto out_release_regions; | ||
157 | } | ||
158 | |||
159 | err = ufshcd_set_dma_mask(pdev); | ||
160 | if (err) { | ||
161 | dev_err(&pdev->dev, "set dma mask failed\n"); | ||
162 | goto out_iounmap; | ||
163 | } | ||
164 | |||
165 | err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq); | ||
166 | if (err) { | ||
167 | dev_err(&pdev->dev, "Initialization failed\n"); | ||
168 | goto out_iounmap; | ||
169 | } | ||
170 | |||
171 | pci_set_drvdata(pdev, hba); | ||
172 | |||
173 | return 0; | ||
174 | |||
175 | out_iounmap: | ||
176 | iounmap(mmio_base); | ||
177 | out_release_regions: | ||
178 | pci_release_regions(pdev); | ||
179 | out_disable: | ||
180 | pci_clear_master(pdev); | ||
181 | pci_disable_device(pdev); | ||
182 | out_error: | ||
183 | return err; | ||
184 | } | ||
185 | |||
186 | static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = { | ||
187 | { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
188 | { } /* terminate list */ | ||
189 | }; | ||
190 | |||
191 | MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl); | ||
192 | |||
193 | static struct pci_driver ufshcd_pci_driver = { | ||
194 | .name = UFSHCD, | ||
195 | .id_table = ufshcd_pci_tbl, | ||
196 | .probe = ufshcd_pci_probe, | ||
197 | .remove = ufshcd_pci_remove, | ||
198 | .shutdown = ufshcd_pci_shutdown, | ||
199 | #ifdef CONFIG_PM | ||
200 | .suspend = ufshcd_pci_suspend, | ||
201 | .resume = ufshcd_pci_resume, | ||
202 | #endif | ||
203 | }; | ||
204 | |||
205 | module_pci_driver(ufshcd_pci_driver); | ||
206 | |||
207 | MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); | ||
208 | MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); | ||
209 | MODULE_DESCRIPTION("UFS host controller PCI glue driver"); | ||
210 | MODULE_LICENSE("GPL"); | ||
211 | MODULE_VERSION(UFSHCD_DRIVER_VERSION); | ||
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5f7c0173d8a0..60fd40c4e4c2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Universal Flash Storage Host controller driver | 2 | * Universal Flash Storage Host controller driver Core |
3 | * | 3 | * |
4 | * This code is based on drivers/scsi/ufs/ufshcd.c | 4 | * This code is based on drivers/scsi/ufs/ufshcd.c |
5 | * Copyright (C) 2011-2013 Samsung India Software Operations | 5 | * Copyright (C) 2011-2013 Samsung India Software Operations |
@@ -33,35 +33,7 @@ | |||
33 | * this program. | 33 | * this program. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/module.h> | 36 | #include "ufshcd.h" |
37 | #include <linux/kernel.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/io.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/spinlock.h> | ||
45 | #include <linux/workqueue.h> | ||
46 | #include <linux/errno.h> | ||
47 | #include <linux/types.h> | ||
48 | #include <linux/wait.h> | ||
49 | #include <linux/bitops.h> | ||
50 | |||
51 | #include <asm/irq.h> | ||
52 | #include <asm/byteorder.h> | ||
53 | #include <scsi/scsi.h> | ||
54 | #include <scsi/scsi_cmnd.h> | ||
55 | #include <scsi/scsi_host.h> | ||
56 | #include <scsi/scsi_tcq.h> | ||
57 | #include <scsi/scsi_dbg.h> | ||
58 | #include <scsi/scsi_eh.h> | ||
59 | |||
60 | #include "ufs.h" | ||
61 | #include "ufshci.h" | ||
62 | |||
63 | #define UFSHCD "ufshcd" | ||
64 | #define UFSHCD_DRIVER_VERSION "0.1" | ||
65 | 37 | ||
66 | enum { | 38 | enum { |
67 | UFSHCD_MAX_CHANNEL = 0, | 39 | UFSHCD_MAX_CHANNEL = 0, |
@@ -92,124 +64,6 @@ enum { | |||
92 | }; | 64 | }; |
93 | 65 | ||
94 | /** | 66 | /** |
95 | * struct uic_command - UIC command structure | ||
96 | * @command: UIC command | ||
97 | * @argument1: UIC command argument 1 | ||
98 | * @argument2: UIC command argument 2 | ||
99 | * @argument3: UIC command argument 3 | ||
100 | * @cmd_active: Indicate if UIC command is outstanding | ||
101 | * @result: UIC command result | ||
102 | */ | ||
103 | struct uic_command { | ||
104 | u32 command; | ||
105 | u32 argument1; | ||
106 | u32 argument2; | ||
107 | u32 argument3; | ||
108 | int cmd_active; | ||
109 | int result; | ||
110 | }; | ||
111 | |||
112 | /** | ||
113 | * struct ufs_hba - per adapter private structure | ||
114 | * @mmio_base: UFSHCI base register address | ||
115 | * @ucdl_base_addr: UFS Command Descriptor base address | ||
116 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address | ||
117 | * @utmrdl_base_addr: UTP Task Management Descriptor base address | ||
118 | * @ucdl_dma_addr: UFS Command Descriptor DMA address | ||
119 | * @utrdl_dma_addr: UTRDL DMA address | ||
120 | * @utmrdl_dma_addr: UTMRDL DMA address | ||
121 | * @host: Scsi_Host instance of the driver | ||
122 | * @dev: device handle | ||
123 | * @lrb: local reference block | ||
124 | * @outstanding_tasks: Bits representing outstanding task requests | ||
125 | * @outstanding_reqs: Bits representing outstanding transfer requests | ||
126 | * @capabilities: UFS Controller Capabilities | ||
127 | * @nutrs: Transfer Request Queue depth supported by controller | ||
128 | * @nutmrs: Task Management Queue depth supported by controller | ||
129 | * @ufs_version: UFS Version to which controller complies | ||
130 | * @irq: Irq number of the controller | ||
131 | * @active_uic_cmd: handle of active UIC command | ||
132 | * @ufshcd_tm_wait_queue: wait queue for task management | ||
133 | * @tm_condition: condition variable for task management | ||
134 | * @ufshcd_state: UFSHCD states | ||
135 | * @int_enable_mask: Interrupt Mask Bits | ||
136 | * @uic_workq: Work queue for UIC completion handling | ||
137 | * @feh_workq: Work queue for fatal controller error handling | ||
138 | * @errors: HBA errors | ||
139 | */ | ||
140 | struct ufs_hba { | ||
141 | void __iomem *mmio_base; | ||
142 | |||
143 | /* Virtual memory reference */ | ||
144 | struct utp_transfer_cmd_desc *ucdl_base_addr; | ||
145 | struct utp_transfer_req_desc *utrdl_base_addr; | ||
146 | struct utp_task_req_desc *utmrdl_base_addr; | ||
147 | |||
148 | /* DMA memory reference */ | ||
149 | dma_addr_t ucdl_dma_addr; | ||
150 | dma_addr_t utrdl_dma_addr; | ||
151 | dma_addr_t utmrdl_dma_addr; | ||
152 | |||
153 | struct Scsi_Host *host; | ||
154 | struct device *dev; | ||
155 | |||
156 | struct ufshcd_lrb *lrb; | ||
157 | |||
158 | unsigned long outstanding_tasks; | ||
159 | unsigned long outstanding_reqs; | ||
160 | |||
161 | u32 capabilities; | ||
162 | int nutrs; | ||
163 | int nutmrs; | ||
164 | u32 ufs_version; | ||
165 | unsigned int irq; | ||
166 | |||
167 | struct uic_command active_uic_cmd; | ||
168 | wait_queue_head_t ufshcd_tm_wait_queue; | ||
169 | unsigned long tm_condition; | ||
170 | |||
171 | u32 ufshcd_state; | ||
172 | u32 int_enable_mask; | ||
173 | |||
174 | /* Work Queues */ | ||
175 | struct work_struct uic_workq; | ||
176 | struct work_struct feh_workq; | ||
177 | |||
178 | /* HBA Errors */ | ||
179 | u32 errors; | ||
180 | }; | ||
181 | |||
182 | /** | ||
183 | * struct ufshcd_lrb - local reference block | ||
184 | * @utr_descriptor_ptr: UTRD address of the command | ||
185 | * @ucd_cmd_ptr: UCD address of the command | ||
186 | * @ucd_rsp_ptr: Response UPIU address for this command | ||
187 | * @ucd_prdt_ptr: PRDT address of the command | ||
188 | * @cmd: pointer to SCSI command | ||
189 | * @sense_buffer: pointer to sense buffer address of the SCSI command | ||
190 | * @sense_bufflen: Length of the sense buffer | ||
191 | * @scsi_status: SCSI status of the command | ||
192 | * @command_type: SCSI, UFS, Query. | ||
193 | * @task_tag: Task tag of the command | ||
194 | * @lun: LUN of the command | ||
195 | */ | ||
196 | struct ufshcd_lrb { | ||
197 | struct utp_transfer_req_desc *utr_descriptor_ptr; | ||
198 | struct utp_upiu_cmd *ucd_cmd_ptr; | ||
199 | struct utp_upiu_rsp *ucd_rsp_ptr; | ||
200 | struct ufshcd_sg_entry *ucd_prdt_ptr; | ||
201 | |||
202 | struct scsi_cmnd *cmd; | ||
203 | u8 *sense_buffer; | ||
204 | unsigned int sense_bufflen; | ||
205 | int scsi_status; | ||
206 | |||
207 | int command_type; | ||
208 | int task_tag; | ||
209 | unsigned int lun; | ||
210 | }; | ||
211 | |||
212 | /** | ||
213 | * ufshcd_get_ufs_version - Get the UFS version supported by the HBA | 67 | * ufshcd_get_ufs_version - Get the UFS version supported by the HBA |
214 | * @hba - Pointer to adapter instance | 68 | * @hba - Pointer to adapter instance |
215 | * | 69 | * |
@@ -422,15 +276,6 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba) | |||
422 | } | 276 | } |
423 | 277 | ||
424 | /** | 278 | /** |
425 | * ufshcd_hba_stop - Send controller to reset state | ||
426 | * @hba: per adapter instance | ||
427 | */ | ||
428 | static inline void ufshcd_hba_stop(struct ufs_hba *hba) | ||
429 | { | ||
430 | writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE)); | ||
431 | } | ||
432 | |||
433 | /** | ||
434 | * ufshcd_hba_start - Start controller initialization sequence | 279 | * ufshcd_hba_start - Start controller initialization sequence |
435 | * @hba: per adapter instance | 280 | * @hba: per adapter instance |
436 | */ | 281 | */ |
@@ -1681,15 +1526,6 @@ static struct scsi_host_template ufshcd_driver_template = { | |||
1681 | }; | 1526 | }; |
1682 | 1527 | ||
1683 | /** | 1528 | /** |
1684 | * ufshcd_pci_shutdown - main function to put the controller in reset state | ||
1685 | * @pdev: pointer to PCI device handle | ||
1686 | */ | ||
1687 | static void ufshcd_pci_shutdown(struct pci_dev *pdev) | ||
1688 | { | ||
1689 | ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev)); | ||
1690 | } | ||
1691 | |||
1692 | /** | ||
1693 | * ufshcd_suspend - suspend power management function | 1529 | * ufshcd_suspend - suspend power management function |
1694 | * @hba: per adapter instance | 1530 | * @hba: per adapter instance |
1695 | * @state: power state | 1531 | * @state: power state |
@@ -1732,43 +1568,6 @@ int ufshcd_resume(struct ufs_hba *hba) | |||
1732 | } | 1568 | } |
1733 | EXPORT_SYMBOL_GPL(ufshcd_resume); | 1569 | EXPORT_SYMBOL_GPL(ufshcd_resume); |
1734 | 1570 | ||
1735 | #ifdef CONFIG_PM | ||
1736 | /** | ||
1737 | * ufshcd_pci_suspend - suspend power management function | ||
1738 | * @pdev: pointer to PCI device handle | ||
1739 | * @state: power state | ||
1740 | * | ||
1741 | * Returns -ENOSYS | ||
1742 | */ | ||
1743 | static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1744 | { | ||
1745 | /* | ||
1746 | * TODO: | ||
1747 | * 1. Call ufshcd_suspend | ||
1748 | * 2. Do bus specific power management | ||
1749 | */ | ||
1750 | |||
1751 | return -ENOSYS; | ||
1752 | } | ||
1753 | |||
1754 | /** | ||
1755 | * ufshcd_pci_resume - resume power management function | ||
1756 | * @pdev: pointer to PCI device handle | ||
1757 | * | ||
1758 | * Returns -ENOSYS | ||
1759 | */ | ||
1760 | static int ufshcd_pci_resume(struct pci_dev *pdev) | ||
1761 | { | ||
1762 | /* | ||
1763 | * TODO: | ||
1764 | * 1. Call ufshcd_resume | ||
1765 | * 2. Do bus specific wake up | ||
1766 | */ | ||
1767 | |||
1768 | return -ENOSYS; | ||
1769 | } | ||
1770 | #endif /* CONFIG_PM */ | ||
1771 | |||
1772 | /** | 1571 | /** |
1773 | * ufshcd_hba_free - free allocated memory for | 1572 | * ufshcd_hba_free - free allocated memory for |
1774 | * host memory space data structures | 1573 | * host memory space data structures |
@@ -1799,44 +1598,6 @@ void ufshcd_remove(struct ufs_hba *hba) | |||
1799 | EXPORT_SYMBOL_GPL(ufshcd_remove); | 1598 | EXPORT_SYMBOL_GPL(ufshcd_remove); |
1800 | 1599 | ||
1801 | /** | 1600 | /** |
1802 | * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space | ||
1803 | * data structure memory | ||
1804 | * @pdev - pointer to PCI handle | ||
1805 | */ | ||
1806 | static void ufshcd_pci_remove(struct pci_dev *pdev) | ||
1807 | { | ||
1808 | struct ufs_hba *hba = pci_get_drvdata(pdev); | ||
1809 | |||
1810 | disable_irq(pdev->irq); | ||
1811 | free_irq(pdev->irq, hba); | ||
1812 | ufshcd_remove(hba); | ||
1813 | pci_release_regions(pdev); | ||
1814 | pci_set_drvdata(pdev, NULL); | ||
1815 | pci_clear_master(pdev); | ||
1816 | pci_disable_device(pdev); | ||
1817 | } | ||
1818 | |||
1819 | /** | ||
1820 | * ufshcd_set_dma_mask - Set dma mask based on the controller | ||
1821 | * addressing capability | ||
1822 | * @pdev: PCI device structure | ||
1823 | * | ||
1824 | * Returns 0 for success, non-zero for failure | ||
1825 | */ | ||
1826 | static int ufshcd_set_dma_mask(struct pci_dev *pdev) | ||
1827 | { | ||
1828 | int err; | ||
1829 | |||
1830 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) | ||
1831 | && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) | ||
1832 | return 0; | ||
1833 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
1834 | if (!err) | ||
1835 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
1836 | return err; | ||
1837 | } | ||
1838 | |||
1839 | /** | ||
1840 | * ufshcd_init - Driver initialization routine | 1601 | * ufshcd_init - Driver initialization routine |
1841 | * @dev: pointer to device handle | 1602 | * @dev: pointer to device handle |
1842 | * @hba_handle: driver private handle | 1603 | * @hba_handle: driver private handle |
@@ -1952,90 +1713,8 @@ out_error: | |||
1952 | } | 1713 | } |
1953 | EXPORT_SYMBOL_GPL(ufshcd_init); | 1714 | EXPORT_SYMBOL_GPL(ufshcd_init); |
1954 | 1715 | ||
1955 | /** | ||
1956 | * ufshcd_pci_probe - probe routine of the driver | ||
1957 | * @pdev: pointer to PCI device handle | ||
1958 | * @id: PCI device id | ||
1959 | * | ||
1960 | * Returns 0 on success, non-zero value on failure | ||
1961 | */ | ||
1962 | static int ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
1963 | { | ||
1964 | struct ufs_hba *hba; | ||
1965 | void __iomem *mmio_base; | ||
1966 | int err; | ||
1967 | |||
1968 | err = pci_enable_device(pdev); | ||
1969 | if (err) { | ||
1970 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
1971 | goto out_error; | ||
1972 | } | ||
1973 | |||
1974 | pci_set_master(pdev); | ||
1975 | |||
1976 | err = pci_request_regions(pdev, UFSHCD); | ||
1977 | if (err < 0) { | ||
1978 | dev_err(&pdev->dev, "request regions failed\n"); | ||
1979 | goto out_disable; | ||
1980 | } | ||
1981 | |||
1982 | mmio_base = pci_ioremap_bar(pdev, 0); | ||
1983 | if (!mmio_base) { | ||
1984 | dev_err(&pdev->dev, "memory map failed\n"); | ||
1985 | err = -ENOMEM; | ||
1986 | goto out_release_regions; | ||
1987 | } | ||
1988 | |||
1989 | err = ufshcd_set_dma_mask(pdev); | ||
1990 | if (err) { | ||
1991 | dev_err(&pdev->dev, "set dma mask failed\n"); | ||
1992 | goto out_iounmap; | ||
1993 | } | ||
1994 | |||
1995 | err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq); | ||
1996 | if (err) { | ||
1997 | dev_err(&pdev->dev, "Initialization failed\n"); | ||
1998 | goto out_iounmap; | ||
1999 | } | ||
2000 | |||
2001 | pci_set_drvdata(pdev, hba); | ||
2002 | |||
2003 | return 0; | ||
2004 | |||
2005 | out_iounmap: | ||
2006 | iounmap(mmio_base); | ||
2007 | out_release_regions: | ||
2008 | pci_release_regions(pdev); | ||
2009 | out_disable: | ||
2010 | pci_clear_master(pdev); | ||
2011 | pci_disable_device(pdev); | ||
2012 | out_error: | ||
2013 | return err; | ||
2014 | } | ||
2015 | |||
2016 | static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = { | ||
2017 | { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
2018 | { } /* terminate list */ | ||
2019 | }; | ||
2020 | |||
2021 | MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl); | ||
2022 | |||
2023 | static struct pci_driver ufshcd_pci_driver = { | ||
2024 | .name = UFSHCD, | ||
2025 | .id_table = ufshcd_pci_tbl, | ||
2026 | .probe = ufshcd_pci_probe, | ||
2027 | .remove = ufshcd_pci_remove, | ||
2028 | .shutdown = ufshcd_pci_shutdown, | ||
2029 | #ifdef CONFIG_PM | ||
2030 | .suspend = ufshcd_pci_suspend, | ||
2031 | .resume = ufshcd_pci_resume, | ||
2032 | #endif | ||
2033 | }; | ||
2034 | |||
2035 | module_pci_driver(ufshcd_pci_driver); | ||
2036 | |||
2037 | MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); | 1716 | MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); |
2038 | MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); | 1717 | MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); |
2039 | MODULE_DESCRIPTION("Generic UFS host controller driver"); | 1718 | MODULE_DESCRIPTION("Generic UFS host controller driver Core"); |
2040 | MODULE_LICENSE("GPL"); | 1719 | MODULE_LICENSE("GPL"); |
2041 | MODULE_VERSION(UFSHCD_DRIVER_VERSION); | 1720 | MODULE_VERSION(UFSHCD_DRIVER_VERSION); |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h new file mode 100644 index 000000000000..6b99a42f5819 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Universal Flash Storage Host controller driver | ||
3 | * | ||
4 | * This code is based on drivers/scsi/ufs/ufshcd.h | ||
5 | * Copyright (C) 2011-2013 Samsung India Software Operations | ||
6 | * | ||
7 | * Authors: | ||
8 | * Santosh Yaraganavi <santosh.sy@samsung.com> | ||
9 | * Vinayak Holikatti <h.vinayak@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * See the COPYING file in the top-level directory or visit | ||
16 | * <http://www.gnu.org/licenses/gpl-2.0.html> | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * This program is provided "AS IS" and "WITH ALL FAULTS" and | ||
24 | * without warranty of any kind. You are solely responsible for | ||
25 | * determining the appropriateness of using and distributing | ||
26 | * the program and assume all risks associated with your exercise | ||
27 | * of rights with respect to the program, including but not limited | ||
28 | * to infringement of third party rights, the risks and costs of | ||
29 | * program errors, damage to or loss of data, programs or equipment, | ||
30 | * and unavailability or interruption of operations. Under no | ||
31 | * circumstances will the contributor of this Program be liable for | ||
32 | * any damages of any kind arising from your use or distribution of | ||
33 | * this program. | ||
34 | */ | ||
35 | |||
36 | #ifndef _UFSHCD_H | ||
37 | #define _UFSHCD_H | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/io.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/spinlock.h> | ||
47 | #include <linux/workqueue.h> | ||
48 | #include <linux/errno.h> | ||
49 | #include <linux/types.h> | ||
50 | #include <linux/wait.h> | ||
51 | #include <linux/bitops.h> | ||
52 | #include <linux/pm_runtime.h> | ||
53 | #include <linux/clk.h> | ||
54 | |||
55 | #include <asm/irq.h> | ||
56 | #include <asm/byteorder.h> | ||
57 | #include <scsi/scsi.h> | ||
58 | #include <scsi/scsi_cmnd.h> | ||
59 | #include <scsi/scsi_host.h> | ||
60 | #include <scsi/scsi_tcq.h> | ||
61 | #include <scsi/scsi_dbg.h> | ||
62 | #include <scsi/scsi_eh.h> | ||
63 | |||
64 | #include "ufs.h" | ||
65 | #include "ufshci.h" | ||
66 | |||
67 | #define UFSHCD "ufshcd" | ||
68 | #define UFSHCD_DRIVER_VERSION "0.2" | ||
69 | |||
70 | /** | ||
71 | * struct uic_command - UIC command structure | ||
72 | * @command: UIC command | ||
73 | * @argument1: UIC command argument 1 | ||
74 | * @argument2: UIC command argument 2 | ||
75 | * @argument3: UIC command argument 3 | ||
76 | * @cmd_active: Indicate if UIC command is outstanding | ||
77 | * @result: UIC command result | ||
78 | */ | ||
79 | struct uic_command { | ||
80 | u32 command; | ||
81 | u32 argument1; | ||
82 | u32 argument2; | ||
83 | u32 argument3; | ||
84 | int cmd_active; | ||
85 | int result; | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * struct ufshcd_lrb - local reference block | ||
90 | * @utr_descriptor_ptr: UTRD address of the command | ||
91 | * @ucd_cmd_ptr: UCD address of the command | ||
92 | * @ucd_rsp_ptr: Response UPIU address for this command | ||
93 | * @ucd_prdt_ptr: PRDT address of the command | ||
94 | * @cmd: pointer to SCSI command | ||
95 | * @sense_buffer: pointer to sense buffer address of the SCSI command | ||
96 | * @sense_bufflen: Length of the sense buffer | ||
97 | * @scsi_status: SCSI status of the command | ||
98 | * @command_type: SCSI, UFS, Query. | ||
99 | * @task_tag: Task tag of the command | ||
100 | * @lun: LUN of the command | ||
101 | */ | ||
102 | struct ufshcd_lrb { | ||
103 | struct utp_transfer_req_desc *utr_descriptor_ptr; | ||
104 | struct utp_upiu_cmd *ucd_cmd_ptr; | ||
105 | struct utp_upiu_rsp *ucd_rsp_ptr; | ||
106 | struct ufshcd_sg_entry *ucd_prdt_ptr; | ||
107 | |||
108 | struct scsi_cmnd *cmd; | ||
109 | u8 *sense_buffer; | ||
110 | unsigned int sense_bufflen; | ||
111 | int scsi_status; | ||
112 | |||
113 | int command_type; | ||
114 | int task_tag; | ||
115 | unsigned int lun; | ||
116 | }; | ||
117 | |||
118 | |||
119 | /** | ||
120 | * struct ufs_hba - per adapter private structure | ||
121 | * @mmio_base: UFSHCI base register address | ||
122 | * @ucdl_base_addr: UFS Command Descriptor base address | ||
123 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address | ||
124 | * @utmrdl_base_addr: UTP Task Management Descriptor base address | ||
125 | * @ucdl_dma_addr: UFS Command Descriptor DMA address | ||
126 | * @utrdl_dma_addr: UTRDL DMA address | ||
127 | * @utmrdl_dma_addr: UTMRDL DMA address | ||
128 | * @host: Scsi_Host instance of the driver | ||
129 | * @dev: device handle | ||
130 | * @lrb: local reference block | ||
131 | * @outstanding_tasks: Bits representing outstanding task requests | ||
132 | * @outstanding_reqs: Bits representing outstanding transfer requests | ||
133 | * @capabilities: UFS Controller Capabilities | ||
134 | * @nutrs: Transfer Request Queue depth supported by controller | ||
135 | * @nutmrs: Task Management Queue depth supported by controller | ||
136 | * @ufs_version: UFS Version to which controller complies | ||
137 | * @irq: Irq number of the controller | ||
138 | * @active_uic_cmd: handle of active UIC command | ||
139 | * @ufshcd_tm_wait_queue: wait queue for task management | ||
140 | * @tm_condition: condition variable for task management | ||
141 | * @ufshcd_state: UFSHCD states | ||
142 | * @int_enable_mask: Interrupt Mask Bits | ||
143 | * @uic_workq: Work queue for UIC completion handling | ||
144 | * @feh_workq: Work queue for fatal controller error handling | ||
145 | * @errors: HBA errors | ||
146 | */ | ||
147 | struct ufs_hba { | ||
148 | void __iomem *mmio_base; | ||
149 | |||
150 | /* Virtual memory reference */ | ||
151 | struct utp_transfer_cmd_desc *ucdl_base_addr; | ||
152 | struct utp_transfer_req_desc *utrdl_base_addr; | ||
153 | struct utp_task_req_desc *utmrdl_base_addr; | ||
154 | |||
155 | /* DMA memory reference */ | ||
156 | dma_addr_t ucdl_dma_addr; | ||
157 | dma_addr_t utrdl_dma_addr; | ||
158 | dma_addr_t utmrdl_dma_addr; | ||
159 | |||
160 | struct Scsi_Host *host; | ||
161 | struct device *dev; | ||
162 | |||
163 | struct ufshcd_lrb *lrb; | ||
164 | |||
165 | unsigned long outstanding_tasks; | ||
166 | unsigned long outstanding_reqs; | ||
167 | |||
168 | u32 capabilities; | ||
169 | int nutrs; | ||
170 | int nutmrs; | ||
171 | u32 ufs_version; | ||
172 | unsigned int irq; | ||
173 | |||
174 | struct uic_command active_uic_cmd; | ||
175 | wait_queue_head_t ufshcd_tm_wait_queue; | ||
176 | unsigned long tm_condition; | ||
177 | |||
178 | u32 ufshcd_state; | ||
179 | u32 int_enable_mask; | ||
180 | |||
181 | /* Work Queues */ | ||
182 | struct work_struct uic_workq; | ||
183 | struct work_struct feh_workq; | ||
184 | |||
185 | /* HBA Errors */ | ||
186 | u32 errors; | ||
187 | }; | ||
188 | |||
189 | int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * , | ||
190 | unsigned int); | ||
191 | void ufshcd_remove(struct ufs_hba *); | ||
192 | |||
193 | /** | ||
194 | * ufshcd_hba_stop - Send controller to reset state | ||
195 | * @hba: per adapter instance | ||
196 | */ | ||
197 | static inline void ufshcd_hba_stop(struct ufs_hba *hba) | ||
198 | { | ||
199 | writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE)); | ||
200 | } | ||
201 | |||
202 | #endif /* End of Header */ | ||