xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision b8246f88468440ac596238ff402bcb636053d657)
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"
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 
265697a564SGovind Singh static const struct ath11k_msi_config msi_config = {
275697a564SGovind Singh 	.total_vectors = 32,
285697a564SGovind Singh 	.total_users = 4,
295697a564SGovind Singh 	.users = (struct ath11k_msi_user[]) {
305697a564SGovind Singh 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
315697a564SGovind Singh 		{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
325697a564SGovind Singh 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
335697a564SGovind Singh 		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
345697a564SGovind Singh 	},
355697a564SGovind Singh };
365697a564SGovind Singh 
375697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
385697a564SGovind Singh {
395697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
405697a564SGovind Singh 	struct msi_desc *msi_desc;
415697a564SGovind Singh 	int num_vectors;
425697a564SGovind Singh 	int ret;
435697a564SGovind Singh 
445697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
455697a564SGovind Singh 					    msi_config.total_vectors,
465697a564SGovind Singh 					    msi_config.total_vectors,
475697a564SGovind Singh 					    PCI_IRQ_MSI);
485697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
495697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
505697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
515697a564SGovind Singh 
525697a564SGovind Singh 		if (num_vectors >= 0)
535697a564SGovind Singh 			return -EINVAL;
545697a564SGovind Singh 		else
555697a564SGovind Singh 			return num_vectors;
565697a564SGovind Singh 	}
575697a564SGovind Singh 
585697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
595697a564SGovind Singh 	if (!msi_desc) {
605697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
615697a564SGovind Singh 		ret = -EINVAL;
625697a564SGovind Singh 		goto free_msi_vector;
635697a564SGovind Singh 	}
645697a564SGovind Singh 
655697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
665697a564SGovind Singh 
675697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
685697a564SGovind Singh 
695697a564SGovind Singh 	return 0;
705697a564SGovind Singh 
715697a564SGovind Singh free_msi_vector:
725697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
735697a564SGovind Singh 
745697a564SGovind Singh 	return ret;
755697a564SGovind Singh }
765697a564SGovind Singh 
775697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
785697a564SGovind Singh {
795697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
805697a564SGovind Singh }
815697a564SGovind 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;
1965697a564SGovind 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 
2055697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
2065697a564SGovind Singh 	if (ret) {
2075697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
2085697a564SGovind Singh 		goto err_pci_free_region;
2095697a564SGovind Singh 	}
2105697a564SGovind Singh 
211*b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
212*b8246f88SKalle Valo 	if (ret)
213*b8246f88SKalle Valo 		goto err_pci_disable_msi;
214*b8246f88SKalle Valo 
2156e0355afSGovind Singh 	return 0;
2165762613eSGovind Singh 
217*b8246f88SKalle Valo err_pci_disable_msi:
218*b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
219*b8246f88SKalle Valo 
2205697a564SGovind Singh err_pci_free_region:
2215697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
2225697a564SGovind Singh 
2235762613eSGovind Singh err_free_core:
2245762613eSGovind Singh 	ath11k_core_free(ab);
2255697a564SGovind Singh 
2265762613eSGovind Singh 	return ret;
2276e0355afSGovind Singh }
2286e0355afSGovind Singh 
2296e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
2306e0355afSGovind Singh {
2316e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
2325762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
2336e0355afSGovind Singh 
2346e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
2355697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
2365762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
2376e0355afSGovind Singh 	ath11k_core_free(ab);
2386e0355afSGovind Singh }
2396e0355afSGovind Singh 
2406e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
2416e0355afSGovind Singh 	.name = "ath11k_pci",
2426e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
2436e0355afSGovind Singh 	.probe = ath11k_pci_probe,
2446e0355afSGovind Singh 	.remove = ath11k_pci_remove,
2456e0355afSGovind Singh };
2466e0355afSGovind Singh 
2476e0355afSGovind Singh static int ath11k_pci_init(void)
2486e0355afSGovind Singh {
2496e0355afSGovind Singh 	int ret;
2506e0355afSGovind Singh 
2516e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
2526e0355afSGovind Singh 	if (ret)
2536e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
2546e0355afSGovind Singh 		       ret);
2556e0355afSGovind Singh 
2566e0355afSGovind Singh 	return ret;
2576e0355afSGovind Singh }
2586e0355afSGovind Singh module_init(ath11k_pci_init);
2596e0355afSGovind Singh 
2606e0355afSGovind Singh static void ath11k_pci_exit(void)
2616e0355afSGovind Singh {
2626e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
2636e0355afSGovind Singh }
2646e0355afSGovind Singh 
2656e0355afSGovind Singh module_exit(ath11k_pci_exit);
2666e0355afSGovind Singh 
2676e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
2686e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
269