xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 5697a564d369412ca988696f43dacad59b5f7efb)
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