1 /* 2 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. 3 * 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 17 #include <linux/module.h> 18 #include <linux/pci.h> 19 #include <linux/moduleparam.h> 20 #include <linux/interrupt.h> 21 22 #include "wil6210.h" 23 24 static int use_msi = 1; 25 module_param(use_msi, int, S_IRUGO); 26 MODULE_PARM_DESC(use_msi, 27 " Use MSI interrupt: " 28 "0 - don't, 1 - (default) - single, or 3"); 29 30 static bool debug_fw; /* = false; */ 31 module_param(debug_fw, bool, S_IRUGO); 32 MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); 33 34 static 35 void wil_set_capabilities(struct wil6210_priv *wil) 36 { 37 u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); 38 39 bitmap_zero(wil->hw_capabilities, hw_capability_last); 40 41 switch (rev_id) { 42 case JTAG_DEV_ID_MARLON_B0: 43 wil->hw_name = "Marlon B0"; 44 wil->hw_version = HW_VER_MARLON_B0; 45 break; 46 case JTAG_DEV_ID_SPARROW_A0: 47 wil->hw_name = "Sparrow A0"; 48 wil->hw_version = HW_VER_SPARROW_A0; 49 break; 50 case JTAG_DEV_ID_SPARROW_A1: 51 wil->hw_name = "Sparrow A1"; 52 wil->hw_version = HW_VER_SPARROW_A1; 53 break; 54 case JTAG_DEV_ID_SPARROW_B0: 55 wil->hw_name = "Sparrow B0"; 56 wil->hw_version = HW_VER_SPARROW_B0; 57 break; 58 default: 59 wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id); 60 wil->hw_name = "Unknown"; 61 wil->hw_version = HW_VER_UNKNOWN; 62 } 63 64 wil_info(wil, "Board hardware is %s\n", wil->hw_name); 65 66 if (wil->hw_version >= HW_VER_SPARROW_A0) 67 set_bit(hw_capability_reset_v2, wil->hw_capabilities); 68 69 if (wil->hw_version >= HW_VER_SPARROW_B0) 70 set_bit(hw_capability_advanced_itr_moderation, 71 wil->hw_capabilities); 72 } 73 74 void wil_disable_irq(struct wil6210_priv *wil) 75 { 76 int irq = wil->pdev->irq; 77 78 disable_irq(irq); 79 if (wil->n_msi == 3) { 80 disable_irq(irq + 1); 81 disable_irq(irq + 2); 82 } 83 } 84 85 void wil_enable_irq(struct wil6210_priv *wil) 86 { 87 int irq = wil->pdev->irq; 88 89 enable_irq(irq); 90 if (wil->n_msi == 3) { 91 enable_irq(irq + 1); 92 enable_irq(irq + 2); 93 } 94 } 95 96 /* Bus ops */ 97 static int wil_if_pcie_enable(struct wil6210_priv *wil) 98 { 99 struct pci_dev *pdev = wil->pdev; 100 int rc; 101 /* on platforms with buggy ACPI, pdev->msi_enabled may be set to 102 * allow pci_enable_device to work. This indicates INTx was not routed 103 * and only MSI should be used 104 */ 105 int msi_only = pdev->msi_enabled; 106 107 wil_dbg_misc(wil, "%s()\n", __func__); 108 109 pdev->msi_enabled = 0; 110 111 pci_set_master(pdev); 112 113 /* 114 * how many MSI interrupts to request? 115 */ 116 switch (use_msi) { 117 case 3: 118 case 1: 119 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); 120 break; 121 case 0: 122 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); 123 break; 124 default: 125 wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); 126 use_msi = 1; 127 } 128 129 if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { 130 wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); 131 use_msi = 1; 132 } 133 134 if (use_msi == 1 && pci_enable_msi(pdev)) { 135 wil_err(wil, "pci_enable_msi failed, use INTx\n"); 136 use_msi = 0; 137 } 138 139 wil->n_msi = use_msi; 140 141 if ((wil->n_msi == 0) && msi_only) { 142 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); 143 rc = -ENODEV; 144 goto stop_master; 145 } 146 147 rc = wil6210_init_irq(wil, pdev->irq); 148 if (rc) 149 goto stop_master; 150 151 /* need reset here to obtain MAC */ 152 mutex_lock(&wil->mutex); 153 rc = wil_reset(wil); 154 mutex_unlock(&wil->mutex); 155 if (debug_fw) 156 rc = 0; 157 if (rc) 158 goto release_irq; 159 160 return 0; 161 162 release_irq: 163 wil6210_fini_irq(wil, pdev->irq); 164 /* safe to call if no MSI */ 165 pci_disable_msi(pdev); 166 stop_master: 167 pci_clear_master(pdev); 168 return rc; 169 } 170 171 static int wil_if_pcie_disable(struct wil6210_priv *wil) 172 { 173 struct pci_dev *pdev = wil->pdev; 174 175 wil_dbg_misc(wil, "%s()\n", __func__); 176 177 pci_clear_master(pdev); 178 /* disable and release IRQ */ 179 wil6210_fini_irq(wil, pdev->irq); 180 /* safe to call if no MSI */ 181 pci_disable_msi(pdev); 182 /* TODO: disable HW */ 183 184 return 0; 185 } 186 187 static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) 188 { 189 struct wil6210_priv *wil; 190 struct device *dev = &pdev->dev; 191 void __iomem *csr; 192 int rc; 193 194 /* check HW */ 195 dev_info(&pdev->dev, WIL_NAME 196 " device found [%04x:%04x] (rev %x)\n", 197 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); 198 199 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { 200 dev_err(&pdev->dev, "Not " WIL_NAME "? " 201 "BAR0 size is %lu while expecting %lu\n", 202 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); 203 return -ENODEV; 204 } 205 206 rc = pci_enable_device(pdev); 207 if (rc) { 208 dev_err(&pdev->dev, 209 "pci_enable_device failed, retry with MSI only\n"); 210 /* Work around for platforms that can't allocate IRQ: 211 * retry with MSI only 212 */ 213 pdev->msi_enabled = 1; 214 rc = pci_enable_device(pdev); 215 } 216 if (rc) 217 return -ENODEV; 218 /* rollback to err_disable_pdev */ 219 220 rc = pci_request_region(pdev, 0, WIL_NAME); 221 if (rc) { 222 dev_err(&pdev->dev, "pci_request_region failed\n"); 223 goto err_disable_pdev; 224 } 225 /* rollback to err_release_reg */ 226 227 csr = pci_ioremap_bar(pdev, 0); 228 if (!csr) { 229 dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); 230 rc = -ENODEV; 231 goto err_release_reg; 232 } 233 /* rollback to err_iounmap */ 234 dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr); 235 236 wil = wil_if_alloc(dev, csr); 237 if (IS_ERR(wil)) { 238 rc = (int)PTR_ERR(wil); 239 dev_err(dev, "wil_if_alloc failed: %d\n", rc); 240 goto err_iounmap; 241 } 242 /* rollback to if_free */ 243 244 pci_set_drvdata(pdev, wil); 245 wil->pdev = pdev; 246 wil_set_capabilities(wil); 247 wil6210_clear_irq(wil); 248 249 wil->platform_handle = 250 wil_platform_init(&pdev->dev, &wil->platform_ops); 251 252 /* FW should raise IRQ when ready */ 253 rc = wil_if_pcie_enable(wil); 254 if (rc) { 255 wil_err(wil, "Enable device failed\n"); 256 goto if_free; 257 } 258 /* rollback to bus_disable */ 259 260 rc = wil_if_add(wil); 261 if (rc) { 262 wil_err(wil, "wil_if_add failed: %d\n", rc); 263 goto bus_disable; 264 } 265 266 wil6210_debugfs_init(wil); 267 268 /* check FW is alive */ 269 wmi_echo(wil); 270 271 return 0; 272 273 bus_disable: 274 wil_if_pcie_disable(wil); 275 if_free: 276 if (wil->platform_ops.uninit) 277 wil->platform_ops.uninit(wil->platform_handle); 278 wil_if_free(wil); 279 err_iounmap: 280 pci_iounmap(pdev, csr); 281 err_release_reg: 282 pci_release_region(pdev, 0); 283 err_disable_pdev: 284 pci_disable_device(pdev); 285 286 return rc; 287 } 288 289 static void wil_pcie_remove(struct pci_dev *pdev) 290 { 291 struct wil6210_priv *wil = pci_get_drvdata(pdev); 292 void __iomem *csr = wil->csr; 293 294 wil_dbg_misc(wil, "%s()\n", __func__); 295 296 wil6210_debugfs_remove(wil); 297 wil_if_remove(wil); 298 wil_if_pcie_disable(wil); 299 if (wil->platform_ops.uninit) 300 wil->platform_ops.uninit(wil->platform_handle); 301 wil_if_free(wil); 302 pci_iounmap(pdev, csr); 303 pci_release_region(pdev, 0); 304 pci_disable_device(pdev); 305 } 306 307 static const struct pci_device_id wil6210_pcie_ids[] = { 308 { PCI_DEVICE(0x1ae9, 0x0301) }, 309 { PCI_DEVICE(0x1ae9, 0x0310) }, 310 { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ 311 { /* end: all zeroes */ }, 312 }; 313 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 314 315 static struct pci_driver wil6210_driver = { 316 .probe = wil_pcie_probe, 317 .remove = wil_pcie_remove, 318 .id_table = wil6210_pcie_ids, 319 .name = WIL_NAME, 320 }; 321 322 module_pci_driver(wil6210_driver); 323 324 MODULE_LICENSE("Dual BSD/GPL"); 325 MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); 326 MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); 327