16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear 26e0355afSGovind Singh /* 36e0355afSGovind Singh * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 46e0355afSGovind Singh */ 56e0355afSGovind Singh 66e0355afSGovind Singh #include <linux/module.h> 7*5697a564SGovind Singh #include <linux/msi.h> 86e0355afSGovind Singh #include <linux/pci.h> 96e0355afSGovind Singh 105762613eSGovind Singh #include "pci.h" 116e0355afSGovind Singh #include "core.h" 126e0355afSGovind Singh #include "debug.h" 136e0355afSGovind Singh 145762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 155762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 165762613eSGovind Singh 176e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 186e0355afSGovind Singh 196e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 206e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 216e0355afSGovind Singh {0} 226e0355afSGovind Singh }; 236e0355afSGovind Singh 246e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 256e0355afSGovind Singh 26*5697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 27*5697a564SGovind Singh .total_vectors = 32, 28*5697a564SGovind Singh .total_users = 4, 29*5697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 30*5697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 31*5697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 32*5697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 33*5697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 34*5697a564SGovind Singh }, 35*5697a564SGovind Singh }; 36*5697a564SGovind Singh 37*5697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 38*5697a564SGovind Singh { 39*5697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 40*5697a564SGovind Singh struct msi_desc *msi_desc; 41*5697a564SGovind Singh int num_vectors; 42*5697a564SGovind Singh int ret; 43*5697a564SGovind Singh 44*5697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 45*5697a564SGovind Singh msi_config.total_vectors, 46*5697a564SGovind Singh msi_config.total_vectors, 47*5697a564SGovind Singh PCI_IRQ_MSI); 48*5697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 49*5697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 50*5697a564SGovind Singh msi_config.total_vectors, num_vectors); 51*5697a564SGovind Singh 52*5697a564SGovind Singh if (num_vectors >= 0) 53*5697a564SGovind Singh return -EINVAL; 54*5697a564SGovind Singh else 55*5697a564SGovind Singh return num_vectors; 56*5697a564SGovind Singh } 57*5697a564SGovind Singh 58*5697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 59*5697a564SGovind Singh if (!msi_desc) { 60*5697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 61*5697a564SGovind Singh ret = -EINVAL; 62*5697a564SGovind Singh goto free_msi_vector; 63*5697a564SGovind Singh } 64*5697a564SGovind Singh 65*5697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 66*5697a564SGovind Singh 67*5697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 68*5697a564SGovind Singh 69*5697a564SGovind Singh return 0; 70*5697a564SGovind Singh 71*5697a564SGovind Singh free_msi_vector: 72*5697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 73*5697a564SGovind Singh 74*5697a564SGovind Singh return ret; 75*5697a564SGovind Singh } 76*5697a564SGovind Singh 77*5697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 78*5697a564SGovind Singh { 79*5697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 80*5697a564SGovind Singh } 81*5697a564SGovind Singh 825762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 835762613eSGovind Singh { 845762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 855762613eSGovind Singh u16 device_id; 865762613eSGovind Singh int ret = 0; 875762613eSGovind Singh 885762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 895762613eSGovind Singh if (device_id != ab_pci->dev_id) { 905762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 915762613eSGovind Singh device_id, ab_pci->dev_id); 925762613eSGovind Singh ret = -EIO; 935762613eSGovind Singh goto out; 945762613eSGovind Singh } 955762613eSGovind Singh 965762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 975762613eSGovind Singh if (ret) { 985762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 995762613eSGovind Singh goto out; 1005762613eSGovind Singh } 1015762613eSGovind Singh 1025762613eSGovind Singh ret = pci_enable_device(pdev); 1035762613eSGovind Singh if (ret) { 1045762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 1055762613eSGovind Singh goto out; 1065762613eSGovind Singh } 1075762613eSGovind Singh 1085762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 1095762613eSGovind Singh if (ret) { 1105762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 1115762613eSGovind Singh goto disable_device; 1125762613eSGovind Singh } 1135762613eSGovind Singh 1145762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 1155762613eSGovind Singh if (ret) { 1165762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 1175762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 1185762613eSGovind Singh goto release_region; 1195762613eSGovind Singh } 1205762613eSGovind Singh 1215762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 1225762613eSGovind Singh if (ret) { 1235762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 1245762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 1255762613eSGovind Singh goto release_region; 1265762613eSGovind Singh } 1275762613eSGovind Singh 1285762613eSGovind Singh pci_set_master(pdev); 1295762613eSGovind Singh 1305762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 1315762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 1325762613eSGovind Singh if (!ab->mem) { 1335762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 1345762613eSGovind Singh ret = -EIO; 1355762613eSGovind Singh goto clear_master; 1365762613eSGovind Singh } 1375762613eSGovind Singh 1385762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 1395762613eSGovind Singh return 0; 1405762613eSGovind Singh 1415762613eSGovind Singh clear_master: 1425762613eSGovind Singh pci_clear_master(pdev); 1435762613eSGovind Singh release_region: 1445762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 1455762613eSGovind Singh disable_device: 1465762613eSGovind Singh pci_disable_device(pdev); 1475762613eSGovind Singh out: 1485762613eSGovind Singh return ret; 1495762613eSGovind Singh } 1505762613eSGovind Singh 1515762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 1525762613eSGovind Singh { 1535762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 1545762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 1555762613eSGovind Singh 1565762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 1575762613eSGovind Singh ab->mem = NULL; 1585762613eSGovind Singh pci_clear_master(pci_dev); 1595762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 1605762613eSGovind Singh if (pci_is_enabled(pci_dev)) 1615762613eSGovind Singh pci_disable_device(pci_dev); 1625762613eSGovind Singh } 1635762613eSGovind Singh 1646e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 1656e0355afSGovind Singh const struct pci_device_id *pci_dev) 1666e0355afSGovind Singh { 1676e0355afSGovind Singh struct ath11k_base *ab; 1685762613eSGovind Singh struct ath11k_pci *ab_pci; 1696e0355afSGovind Singh enum ath11k_hw_rev hw_rev; 1705762613eSGovind Singh int ret; 1716e0355afSGovind Singh 1726e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 1736e0355afSGovind Singh 1746e0355afSGovind Singh switch (pci_dev->device) { 1756e0355afSGovind Singh case QCA6390_DEVICE_ID: 1766e0355afSGovind Singh hw_rev = ATH11K_HW_QCA6390_HW20; 1776e0355afSGovind Singh break; 1786e0355afSGovind Singh default: 1796e0355afSGovind Singh dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 1806e0355afSGovind Singh pci_dev->device); 1816e0355afSGovind Singh return -ENOTSUPP; 1826e0355afSGovind Singh } 1836e0355afSGovind Singh 1845762613eSGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); 1856e0355afSGovind Singh if (!ab) { 1866e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 1876e0355afSGovind Singh return -ENOMEM; 1886e0355afSGovind Singh } 1896e0355afSGovind Singh 1906e0355afSGovind Singh ab->dev = &pdev->dev; 1916e0355afSGovind Singh ab->hw_rev = hw_rev; 1926e0355afSGovind Singh pci_set_drvdata(pdev, ab); 1935762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 1945762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 1955762613eSGovind Singh ab_pci->ab = ab; 196*5697a564SGovind Singh ab_pci->pdev = pdev; 1975762613eSGovind Singh pci_set_drvdata(pdev, ab); 1985762613eSGovind Singh 1995762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 2005762613eSGovind Singh if (ret) { 2015762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 2025762613eSGovind Singh goto err_free_core; 2035762613eSGovind Singh } 2046e0355afSGovind Singh 205*5697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 206*5697a564SGovind Singh if (ret) { 207*5697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 208*5697a564SGovind Singh goto err_pci_free_region; 209*5697a564SGovind Singh } 210*5697a564SGovind Singh 2116e0355afSGovind Singh return 0; 2125762613eSGovind Singh 213*5697a564SGovind Singh err_pci_free_region: 214*5697a564SGovind Singh ath11k_pci_free_region(ab_pci); 215*5697a564SGovind Singh 2165762613eSGovind Singh err_free_core: 2175762613eSGovind Singh ath11k_core_free(ab); 218*5697a564SGovind Singh 2195762613eSGovind Singh return ret; 2206e0355afSGovind Singh } 2216e0355afSGovind Singh 2226e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 2236e0355afSGovind Singh { 2246e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 2255762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 2266e0355afSGovind Singh 2276e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 228*5697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 2295762613eSGovind Singh ath11k_pci_free_region(ab_pci); 2306e0355afSGovind Singh ath11k_core_free(ab); 2316e0355afSGovind Singh } 2326e0355afSGovind Singh 2336e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 2346e0355afSGovind Singh .name = "ath11k_pci", 2356e0355afSGovind Singh .id_table = ath11k_pci_id_table, 2366e0355afSGovind Singh .probe = ath11k_pci_probe, 2376e0355afSGovind Singh .remove = ath11k_pci_remove, 2386e0355afSGovind Singh }; 2396e0355afSGovind Singh 2406e0355afSGovind Singh static int ath11k_pci_init(void) 2416e0355afSGovind Singh { 2426e0355afSGovind Singh int ret; 2436e0355afSGovind Singh 2446e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 2456e0355afSGovind Singh if (ret) 2466e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 2476e0355afSGovind Singh ret); 2486e0355afSGovind Singh 2496e0355afSGovind Singh return ret; 2506e0355afSGovind Singh } 2516e0355afSGovind Singh module_init(ath11k_pci_init); 2526e0355afSGovind Singh 2536e0355afSGovind Singh static void ath11k_pci_exit(void) 2546e0355afSGovind Singh { 2556e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 2566e0355afSGovind Singh } 2576e0355afSGovind Singh 2586e0355afSGovind Singh module_exit(ath11k_pci_exit); 2596e0355afSGovind Singh 2606e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 2616e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 262