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> 75697a564SGovind Singh #include <linux/msi.h> 86e0355afSGovind Singh #include <linux/pci.h> 96e0355afSGovind Singh 105762613eSGovind Singh #include "pci.h" 116e0355afSGovind Singh #include "core.h" 12*1399fb87SGovind Singh #include "hif.h" 13*1399fb87SGovind Singh #include "mhi.h" 146e0355afSGovind Singh #include "debug.h" 156e0355afSGovind Singh 165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 185762613eSGovind Singh 196e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 206e0355afSGovind Singh 216e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 226e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 236e0355afSGovind Singh {0} 246e0355afSGovind Singh }; 256e0355afSGovind Singh 266e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 276e0355afSGovind Singh 285697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 295697a564SGovind Singh .total_vectors = 32, 305697a564SGovind Singh .total_users = 4, 315697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 325697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 335697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 345697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 355697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 365697a564SGovind Singh }, 375697a564SGovind Singh }; 385697a564SGovind Singh 39*1399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 40*1399fb87SGovind Singh { 41*1399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 42*1399fb87SGovind Singh 43*1399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 44*1399fb87SGovind Singh } 45*1399fb87SGovind Singh 46*1399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 47*1399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 48*1399fb87SGovind Singh u32 *base_vector) 49*1399fb87SGovind Singh { 50*1399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 51*1399fb87SGovind Singh int idx; 52*1399fb87SGovind Singh 53*1399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 54*1399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 55*1399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 56*1399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 57*1399fb87SGovind Singh + ab_pci->msi_ep_base_data; 58*1399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 59*1399fb87SGovind Singh 60*1399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 61*1399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 62*1399fb87SGovind Singh *base_vector); 63*1399fb87SGovind Singh 64*1399fb87SGovind Singh return 0; 65*1399fb87SGovind Singh } 66*1399fb87SGovind Singh } 67*1399fb87SGovind Singh 68*1399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 69*1399fb87SGovind Singh 70*1399fb87SGovind Singh return -EINVAL; 71*1399fb87SGovind Singh } 72*1399fb87SGovind Singh 735697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 745697a564SGovind Singh { 755697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 765697a564SGovind Singh struct msi_desc *msi_desc; 775697a564SGovind Singh int num_vectors; 785697a564SGovind Singh int ret; 795697a564SGovind Singh 805697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 815697a564SGovind Singh msi_config.total_vectors, 825697a564SGovind Singh msi_config.total_vectors, 835697a564SGovind Singh PCI_IRQ_MSI); 845697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 855697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 865697a564SGovind Singh msi_config.total_vectors, num_vectors); 875697a564SGovind Singh 885697a564SGovind Singh if (num_vectors >= 0) 895697a564SGovind Singh return -EINVAL; 905697a564SGovind Singh else 915697a564SGovind Singh return num_vectors; 925697a564SGovind Singh } 935697a564SGovind Singh 945697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 955697a564SGovind Singh if (!msi_desc) { 965697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 975697a564SGovind Singh ret = -EINVAL; 985697a564SGovind Singh goto free_msi_vector; 995697a564SGovind Singh } 1005697a564SGovind Singh 1015697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 1025697a564SGovind Singh 1035697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 1045697a564SGovind Singh 1055697a564SGovind Singh return 0; 1065697a564SGovind Singh 1075697a564SGovind Singh free_msi_vector: 1085697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 1095697a564SGovind Singh 1105697a564SGovind Singh return ret; 1115697a564SGovind Singh } 1125697a564SGovind Singh 1135697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 1145697a564SGovind Singh { 1155697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 1165697a564SGovind Singh } 1175697a564SGovind Singh 1185762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 1195762613eSGovind Singh { 1205762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 1215762613eSGovind Singh u16 device_id; 1225762613eSGovind Singh int ret = 0; 1235762613eSGovind Singh 1245762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 1255762613eSGovind Singh if (device_id != ab_pci->dev_id) { 1265762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 1275762613eSGovind Singh device_id, ab_pci->dev_id); 1285762613eSGovind Singh ret = -EIO; 1295762613eSGovind Singh goto out; 1305762613eSGovind Singh } 1315762613eSGovind Singh 1325762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 1335762613eSGovind Singh if (ret) { 1345762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 1355762613eSGovind Singh goto out; 1365762613eSGovind Singh } 1375762613eSGovind Singh 1385762613eSGovind Singh ret = pci_enable_device(pdev); 1395762613eSGovind Singh if (ret) { 1405762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 1415762613eSGovind Singh goto out; 1425762613eSGovind Singh } 1435762613eSGovind Singh 1445762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 1455762613eSGovind Singh if (ret) { 1465762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 1475762613eSGovind Singh goto disable_device; 1485762613eSGovind Singh } 1495762613eSGovind Singh 1505762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 1515762613eSGovind Singh if (ret) { 1525762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 1535762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 1545762613eSGovind Singh goto release_region; 1555762613eSGovind Singh } 1565762613eSGovind Singh 1575762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 1585762613eSGovind Singh if (ret) { 1595762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 1605762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 1615762613eSGovind Singh goto release_region; 1625762613eSGovind Singh } 1635762613eSGovind Singh 1645762613eSGovind Singh pci_set_master(pdev); 1655762613eSGovind Singh 1665762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 1675762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 1685762613eSGovind Singh if (!ab->mem) { 1695762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 1705762613eSGovind Singh ret = -EIO; 1715762613eSGovind Singh goto clear_master; 1725762613eSGovind Singh } 1735762613eSGovind Singh 1745762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 1755762613eSGovind Singh return 0; 1765762613eSGovind Singh 1775762613eSGovind Singh clear_master: 1785762613eSGovind Singh pci_clear_master(pdev); 1795762613eSGovind Singh release_region: 1805762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 1815762613eSGovind Singh disable_device: 1825762613eSGovind Singh pci_disable_device(pdev); 1835762613eSGovind Singh out: 1845762613eSGovind Singh return ret; 1855762613eSGovind Singh } 1865762613eSGovind Singh 1875762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 1885762613eSGovind Singh { 1895762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 1905762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 1915762613eSGovind Singh 1925762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 1935762613eSGovind Singh ab->mem = NULL; 1945762613eSGovind Singh pci_clear_master(pci_dev); 1955762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 1965762613eSGovind Singh if (pci_is_enabled(pci_dev)) 1975762613eSGovind Singh pci_disable_device(pci_dev); 1985762613eSGovind Singh } 1995762613eSGovind Singh 200*1399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 201*1399fb87SGovind Singh { 202*1399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 203*1399fb87SGovind Singh int ret; 204*1399fb87SGovind Singh 205*1399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 206*1399fb87SGovind Singh if (ret) { 207*1399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 208*1399fb87SGovind Singh return ret; 209*1399fb87SGovind Singh } 210*1399fb87SGovind Singh 211*1399fb87SGovind Singh return 0; 212*1399fb87SGovind Singh } 213*1399fb87SGovind Singh 214*1399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 215*1399fb87SGovind Singh { 216*1399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 217*1399fb87SGovind Singh 218*1399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 219*1399fb87SGovind Singh } 220*1399fb87SGovind Singh 221*1399fb87SGovind Singh static __maybe_unused const struct ath11k_hif_ops ath11k_pci_hif_ops = { 222*1399fb87SGovind Singh .power_down = ath11k_pci_power_down, 223*1399fb87SGovind Singh .power_up = ath11k_pci_power_up, 224*1399fb87SGovind Singh }; 225*1399fb87SGovind Singh 2266e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 2276e0355afSGovind Singh const struct pci_device_id *pci_dev) 2286e0355afSGovind Singh { 2296e0355afSGovind Singh struct ath11k_base *ab; 2305762613eSGovind Singh struct ath11k_pci *ab_pci; 2316e0355afSGovind Singh enum ath11k_hw_rev hw_rev; 2325762613eSGovind Singh int ret; 2336e0355afSGovind Singh 2346e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 2356e0355afSGovind Singh 2366e0355afSGovind Singh switch (pci_dev->device) { 2376e0355afSGovind Singh case QCA6390_DEVICE_ID: 2386e0355afSGovind Singh hw_rev = ATH11K_HW_QCA6390_HW20; 2396e0355afSGovind Singh break; 2406e0355afSGovind Singh default: 2416e0355afSGovind Singh dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 2426e0355afSGovind Singh pci_dev->device); 2436e0355afSGovind Singh return -ENOTSUPP; 2446e0355afSGovind Singh } 2456e0355afSGovind Singh 2465762613eSGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); 2476e0355afSGovind Singh if (!ab) { 2486e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 2496e0355afSGovind Singh return -ENOMEM; 2506e0355afSGovind Singh } 2516e0355afSGovind Singh 2526e0355afSGovind Singh ab->dev = &pdev->dev; 2536e0355afSGovind Singh ab->hw_rev = hw_rev; 2546e0355afSGovind Singh pci_set_drvdata(pdev, ab); 2555762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 2565762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 2575762613eSGovind Singh ab_pci->ab = ab; 2585697a564SGovind Singh ab_pci->pdev = pdev; 2595762613eSGovind Singh pci_set_drvdata(pdev, ab); 2605762613eSGovind Singh 2615762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 2625762613eSGovind Singh if (ret) { 2635762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 2645762613eSGovind Singh goto err_free_core; 2655762613eSGovind Singh } 2666e0355afSGovind Singh 2675697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 2685697a564SGovind Singh if (ret) { 2695697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 2705697a564SGovind Singh goto err_pci_free_region; 2715697a564SGovind Singh } 2725697a564SGovind Singh 273b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 274b8246f88SKalle Valo if (ret) 275b8246f88SKalle Valo goto err_pci_disable_msi; 276b8246f88SKalle Valo 277*1399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 278*1399fb87SGovind Singh if (ret) { 279*1399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 280*1399fb87SGovind Singh goto err_pci_disable_msi; 281*1399fb87SGovind Singh } 282*1399fb87SGovind Singh 2836e0355afSGovind Singh return 0; 2845762613eSGovind Singh 285b8246f88SKalle Valo err_pci_disable_msi: 286b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 287b8246f88SKalle Valo 2885697a564SGovind Singh err_pci_free_region: 2895697a564SGovind Singh ath11k_pci_free_region(ab_pci); 2905697a564SGovind Singh 2915762613eSGovind Singh err_free_core: 2925762613eSGovind Singh ath11k_core_free(ab); 2935697a564SGovind Singh 2945762613eSGovind Singh return ret; 2956e0355afSGovind Singh } 2966e0355afSGovind Singh 2976e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 2986e0355afSGovind Singh { 2996e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 3005762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 3016e0355afSGovind Singh 3026e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 303*1399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 3045697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 3055762613eSGovind Singh ath11k_pci_free_region(ab_pci); 3066e0355afSGovind Singh ath11k_core_free(ab); 3076e0355afSGovind Singh } 3086e0355afSGovind Singh 309*1399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 310*1399fb87SGovind Singh { 311*1399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 312*1399fb87SGovind Singh 313*1399fb87SGovind Singh ath11k_pci_power_down(ab); 314*1399fb87SGovind Singh } 315*1399fb87SGovind Singh 3166e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 3176e0355afSGovind Singh .name = "ath11k_pci", 3186e0355afSGovind Singh .id_table = ath11k_pci_id_table, 3196e0355afSGovind Singh .probe = ath11k_pci_probe, 3206e0355afSGovind Singh .remove = ath11k_pci_remove, 321*1399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 3226e0355afSGovind Singh }; 3236e0355afSGovind Singh 3246e0355afSGovind Singh static int ath11k_pci_init(void) 3256e0355afSGovind Singh { 3266e0355afSGovind Singh int ret; 3276e0355afSGovind Singh 3286e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 3296e0355afSGovind Singh if (ret) 3306e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 3316e0355afSGovind Singh ret); 3326e0355afSGovind Singh 3336e0355afSGovind Singh return ret; 3346e0355afSGovind Singh } 3356e0355afSGovind Singh module_init(ath11k_pci_init); 3366e0355afSGovind Singh 3376e0355afSGovind Singh static void ath11k_pci_exit(void) 3386e0355afSGovind Singh { 3396e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 3406e0355afSGovind Singh } 3416e0355afSGovind Singh 3426e0355afSGovind Singh module_exit(ath11k_pci_exit); 3436e0355afSGovind Singh 3446e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 3456e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 346