pcie_bus.c revision 94b7b64c73515bc7689bd9d80e6d2fea536a3cef
1/* 2 * Copyright (c) 2012 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/debugfs.h> 19#include <linux/pci.h> 20#include <linux/moduleparam.h> 21 22#include "wil6210.h" 23 24static int use_msi = 1; 25module_param(use_msi, int, S_IRUGO); 26MODULE_PARM_DESC(use_msi, 27 " Use MSI interrupt: " 28 "0 - don't, 1 - (default) - single, or 3"); 29 30static bool debug_fw; /* = false; */ 31module_param(debug_fw, bool, S_IRUGO); 32MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); 33 34/* Bus ops */ 35static int wil_if_pcie_enable(struct wil6210_priv *wil) 36{ 37 struct pci_dev *pdev = wil->pdev; 38 int rc; 39 40 pci_set_master(pdev); 41 42 /* 43 * how many MSI interrupts to request? 44 */ 45 switch (use_msi) { 46 case 3: 47 case 1: 48 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); 49 break; 50 case 0: 51 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); 52 break; 53 default: 54 wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); 55 use_msi = 1; 56 } 57 58 if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { 59 wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); 60 use_msi = 1; 61 } 62 63 if (use_msi == 1 && pci_enable_msi(pdev)) { 64 wil_err(wil, "pci_enable_msi failed, use INTx\n"); 65 use_msi = 0; 66 } 67 68 wil->n_msi = use_msi; 69 70 rc = wil6210_init_irq(wil, pdev->irq); 71 if (rc) 72 goto stop_master; 73 74 /* need reset here to obtain MAC */ 75 mutex_lock(&wil->mutex); 76 rc = wil_reset(wil); 77 mutex_unlock(&wil->mutex); 78 if (debug_fw) 79 rc = 0; 80 if (rc) 81 goto release_irq; 82 83 return 0; 84 85 release_irq: 86 wil6210_fini_irq(wil, pdev->irq); 87 /* safe to call if no MSI */ 88 pci_disable_msi(pdev); 89 stop_master: 90 pci_clear_master(pdev); 91 return rc; 92} 93 94static int wil_if_pcie_disable(struct wil6210_priv *wil) 95{ 96 struct pci_dev *pdev = wil->pdev; 97 98 pci_clear_master(pdev); 99 /* disable and release IRQ */ 100 wil6210_fini_irq(wil, pdev->irq); 101 /* safe to call if no MSI */ 102 pci_disable_msi(pdev); 103 /* TODO: disable HW */ 104 105 return 0; 106} 107 108static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) 109{ 110 struct wil6210_priv *wil; 111 struct device *dev = &pdev->dev; 112 void __iomem *csr; 113 int rc; 114 115 /* check HW */ 116 dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", 117 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); 118 119 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { 120 dev_err(&pdev->dev, "Not " WIL_NAME "? " 121 "BAR0 size is %lu while expecting %lu\n", 122 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); 123 return -ENODEV; 124 } 125 126 rc = pci_enable_device(pdev); 127 if (rc) { 128 dev_err(&pdev->dev, "pci_enable_device failed\n"); 129 return -ENODEV; 130 } 131 /* rollback to err_disable_pdev */ 132 133 rc = pci_request_region(pdev, 0, WIL_NAME); 134 if (rc) { 135 dev_err(&pdev->dev, "pci_request_region failed\n"); 136 goto err_disable_pdev; 137 } 138 /* rollback to err_release_reg */ 139 140 csr = pci_ioremap_bar(pdev, 0); 141 if (!csr) { 142 dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); 143 rc = -ENODEV; 144 goto err_release_reg; 145 } 146 /* rollback to err_iounmap */ 147 dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr); 148 149 wil = wil_if_alloc(dev, csr); 150 if (IS_ERR(wil)) { 151 rc = (int)PTR_ERR(wil); 152 dev_err(dev, "wil_if_alloc failed: %d\n", rc); 153 goto err_iounmap; 154 } 155 /* rollback to if_free */ 156 157 pci_set_drvdata(pdev, wil); 158 wil->pdev = pdev; 159 160 wil6210_clear_irq(wil); 161 /* FW should raise IRQ when ready */ 162 rc = wil_if_pcie_enable(wil); 163 if (rc) { 164 wil_err(wil, "Enable device failed\n"); 165 goto if_free; 166 } 167 /* rollback to bus_disable */ 168 169 rc = wil_if_add(wil); 170 if (rc) { 171 wil_err(wil, "wil_if_add failed: %d\n", rc); 172 goto bus_disable; 173 } 174 175 wil6210_debugfs_init(wil); 176 177 /* check FW is alive */ 178 wmi_echo(wil); 179 180 return 0; 181 182 bus_disable: 183 wil_if_pcie_disable(wil); 184 if_free: 185 wil_if_free(wil); 186 err_iounmap: 187 pci_iounmap(pdev, csr); 188 err_release_reg: 189 pci_release_region(pdev, 0); 190 err_disable_pdev: 191 pci_disable_device(pdev); 192 193 return rc; 194} 195 196static void wil_pcie_remove(struct pci_dev *pdev) 197{ 198 struct wil6210_priv *wil = pci_get_drvdata(pdev); 199 200 wil6210_debugfs_remove(wil); 201 wil_if_pcie_disable(wil); 202 wil_if_remove(wil); 203 wil_if_free(wil); 204 pci_iounmap(pdev, wil->csr); 205 pci_release_region(pdev, 0); 206 pci_disable_device(pdev); 207} 208 209static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { 210 { PCI_DEVICE(0x1ae9, 0x0301) }, 211 { /* end: all zeroes */ }, 212}; 213MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 214 215static struct pci_driver wil6210_driver = { 216 .probe = wil_pcie_probe, 217 .remove = wil_pcie_remove, 218 .id_table = wil6210_pcie_ids, 219 .name = WIL_NAME, 220}; 221 222module_pci_driver(wil6210_driver); 223 224MODULE_LICENSE("Dual BSD/GPL"); 225MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); 226MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); 227