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