blob: d2a1ca289d900494c6348fdcae922310d6cc24a0 [file] [log] [blame]
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001/*
Vladimir Kondratiev02525a72014-08-06 10:31:51 +03002 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080017#include <linux/module.h>
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080018#include <linux/pci.h>
19#include <linux/moduleparam.h>
20
21#include "wil6210.h"
22
23static int use_msi = 1;
24module_param(use_msi, int, S_IRUGO);
25MODULE_PARM_DESC(use_msi,
26 " Use MSI interrupt: "
27 "0 - don't, 1 - (default) - single, or 3");
28
Vladimir Kondratiev94b7b642014-06-16 19:37:06 +030029static bool debug_fw; /* = false; */
30module_param(debug_fw, bool, S_IRUGO);
31MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
32
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080033/* Bus ops */
34static int wil_if_pcie_enable(struct wil6210_priv *wil)
35{
36 struct pci_dev *pdev = wil->pdev;
37 int rc;
Vladimir Kondratiev2bdc0702014-06-16 19:37:20 +030038 /* on platforms with buggy ACPI, pdev->msi_enabled may be set to
39 * allow pci_enable_device to work. This indicates INTx was not routed
40 * and only MSI should be used
41 */
42 int msi_only = pdev->msi_enabled;
43
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +030044 wil_dbg_misc(wil, "%s()\n", __func__);
45
Vladimir Kondratiev2bdc0702014-06-16 19:37:20 +030046 pdev->msi_enabled = 0;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080047
48 pci_set_master(pdev);
49
50 /*
51 * how many MSI interrupts to request?
52 */
53 switch (use_msi) {
54 case 3:
55 case 1:
Alexander Gordeevb4b39062014-02-18 11:12:04 +010056 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
57 break;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080058 case 0:
Alexander Gordeevb4b39062014-02-18 11:12:04 +010059 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080060 break;
61 default:
Alexander Gordeevb4b39062014-02-18 11:12:04 +010062 wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080063 use_msi = 1;
64 }
Alexander Gordeevb4b39062014-02-18 11:12:04 +010065
66 if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) {
67 wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
68 use_msi = 1;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080069 }
70
Alexander Gordeevb4b39062014-02-18 11:12:04 +010071 if (use_msi == 1 && pci_enable_msi(pdev)) {
72 wil_err(wil, "pci_enable_msi failed, use INTx\n");
73 use_msi = 0;
74 }
75
76 wil->n_msi = use_msi;
77
Vladimir Kondratiev2bdc0702014-06-16 19:37:20 +030078 if ((wil->n_msi == 0) && msi_only) {
79 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
80 rc = -ENODEV;
81 goto stop_master;
82 }
83
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080084 rc = wil6210_init_irq(wil, pdev->irq);
85 if (rc)
86 goto stop_master;
87
88 /* need reset here to obtain MAC */
Vladimir Kondratiev097638a2014-03-17 15:34:25 +020089 mutex_lock(&wil->mutex);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080090 rc = wil_reset(wil);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +020091 mutex_unlock(&wil->mutex);
Vladimir Kondratiev94b7b642014-06-16 19:37:06 +030092 if (debug_fw)
93 rc = 0;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080094 if (rc)
95 goto release_irq;
96
97 return 0;
98
99 release_irq:
100 wil6210_fini_irq(wil, pdev->irq);
101 /* safe to call if no MSI */
102 pci_disable_msi(pdev);
103 stop_master:
104 pci_clear_master(pdev);
105 return rc;
106}
107
108static int wil_if_pcie_disable(struct wil6210_priv *wil)
109{
110 struct pci_dev *pdev = wil->pdev;
111
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +0300112 wil_dbg_misc(wil, "%s()\n", __func__);
113
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800114 pci_clear_master(pdev);
115 /* disable and release IRQ */
116 wil6210_fini_irq(wil, pdev->irq);
117 /* safe to call if no MSI */
118 pci_disable_msi(pdev);
119 /* TODO: disable HW */
120
121 return 0;
122}
123
124static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
125{
126 struct wil6210_priv *wil;
127 struct device *dev = &pdev->dev;
128 void __iomem *csr;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300129 struct wil_board *board = (struct wil_board *)id->driver_data;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800130 int rc;
131
132 /* check HW */
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300133 dev_info(&pdev->dev, WIL_NAME
134 " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800135 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
136
137 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
138 dev_err(&pdev->dev, "Not " WIL_NAME "? "
139 "BAR0 size is %lu while expecting %lu\n",
140 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
141 return -ENODEV;
142 }
143
144 rc = pci_enable_device(pdev);
145 if (rc) {
Vladimir Kondratiev2bdc0702014-06-16 19:37:20 +0300146 dev_err(&pdev->dev,
147 "pci_enable_device failed, retry with MSI only\n");
148 /* Work around for platforms that can't allocate IRQ:
149 * retry with MSI only
150 */
151 pdev->msi_enabled = 1;
152 rc = pci_enable_device(pdev);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800153 }
Vladimir Kondratiev2bdc0702014-06-16 19:37:20 +0300154 if (rc)
155 return -ENODEV;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800156 /* rollback to err_disable_pdev */
157
158 rc = pci_request_region(pdev, 0, WIL_NAME);
159 if (rc) {
160 dev_err(&pdev->dev, "pci_request_region failed\n");
161 goto err_disable_pdev;
162 }
163 /* rollback to err_release_reg */
164
165 csr = pci_ioremap_bar(pdev, 0);
166 if (!csr) {
167 dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
168 rc = -ENODEV;
169 goto err_release_reg;
170 }
171 /* rollback to err_iounmap */
Vladimir Kondratiev39c52ee2014-05-27 14:45:49 +0300172 dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800173
174 wil = wil_if_alloc(dev, csr);
175 if (IS_ERR(wil)) {
176 rc = (int)PTR_ERR(wil);
177 dev_err(dev, "wil_if_alloc failed: %d\n", rc);
178 goto err_iounmap;
179 }
180 /* rollback to if_free */
181
182 pci_set_drvdata(pdev, wil);
183 wil->pdev = pdev;
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300184 wil->board = board;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800185
Vladimir Kondratievf4b5a802014-03-17 15:34:13 +0200186 wil6210_clear_irq(wil);
Vladimir Kondratievf772ebf2014-09-10 16:34:35 +0300187
188 wil->platform_handle =
189 wil_platform_init(&pdev->dev, &wil->platform_ops);
190
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800191 /* FW should raise IRQ when ready */
192 rc = wil_if_pcie_enable(wil);
193 if (rc) {
194 wil_err(wil, "Enable device failed\n");
195 goto if_free;
196 }
197 /* rollback to bus_disable */
198
199 rc = wil_if_add(wil);
200 if (rc) {
201 wil_err(wil, "wil_if_add failed: %d\n", rc);
202 goto bus_disable;
203 }
204
205 wil6210_debugfs_init(wil);
206
207 /* check FW is alive */
208 wmi_echo(wil);
209
210 return 0;
211
212 bus_disable:
213 wil_if_pcie_disable(wil);
214 if_free:
Vladimir Kondratievf772ebf2014-09-10 16:34:35 +0300215 if (wil->platform_ops.uninit)
216 wil->platform_ops.uninit(wil->platform_handle);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800217 wil_if_free(wil);
218 err_iounmap:
219 pci_iounmap(pdev, csr);
220 err_release_reg:
221 pci_release_region(pdev, 0);
222 err_disable_pdev:
223 pci_disable_device(pdev);
224
225 return rc;
226}
227
228static void wil_pcie_remove(struct pci_dev *pdev)
229{
230 struct wil6210_priv *wil = pci_get_drvdata(pdev);
Vladimir Kondratiev560ce302014-08-06 10:32:01 +0300231 void __iomem *csr = wil->csr;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800232
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +0300233 wil_dbg_misc(wil, "%s()\n", __func__);
234
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800235 wil6210_debugfs_remove(wil);
236 wil_if_pcie_disable(wil);
237 wil_if_remove(wil);
Vladimir Kondratievf772ebf2014-09-10 16:34:35 +0300238 if (wil->platform_ops.uninit)
239 wil->platform_ops.uninit(wil->platform_handle);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800240 wil_if_free(wil);
Vladimir Kondratiev560ce302014-08-06 10:32:01 +0300241 pci_iounmap(pdev, csr);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800242 pci_release_region(pdev, 0);
243 pci_disable_device(pdev);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800244}
245
Vladimir Kondratiev65082812014-07-14 09:49:37 +0300246static const struct wil_board wil_board_marlon = {
247 .board = WIL_BOARD_MARLON,
248 .name = "marlon",
249};
250
251static const struct wil_board wil_board_sparrow = {
252 .board = WIL_BOARD_SPARROW,
253 .name = "sparrow",
254};
255
256static const struct pci_device_id wil6210_pcie_ids[] = {
257 { PCI_DEVICE(0x1ae9, 0x0301),
258 .driver_data = (kernel_ulong_t)&wil_board_marlon },
259 { PCI_DEVICE(0x1ae9, 0x0310),
260 .driver_data = (kernel_ulong_t)&wil_board_sparrow },
Vladimir Kondratiev6afd6002014-08-06 10:31:54 +0300261 { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
262 .driver_data = (kernel_ulong_t)&wil_board_sparrow },
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800263 { /* end: all zeroes */ },
264};
265MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
266
267static struct pci_driver wil6210_driver = {
268 .probe = wil_pcie_probe,
269 .remove = wil_pcie_remove,
270 .id_table = wil6210_pcie_ids,
271 .name = WIL_NAME,
272};
273
274module_pci_driver(wil6210_driver);
275
276MODULE_LICENSE("Dual BSD/GPL");
277MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
278MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");