1d9110b0bSSrujanaChalla // SPDX-License-Identifier: GPL-2.0
2d9110b0bSSrujanaChalla /* Marvell OcteonTX CPT driver
3d9110b0bSSrujanaChalla  *
4d9110b0bSSrujanaChalla  * Copyright (C) 2019 Marvell International Ltd.
5d9110b0bSSrujanaChalla  *
6d9110b0bSSrujanaChalla  * This program is free software; you can redistribute it and/or modify
7d9110b0bSSrujanaChalla  * it under the terms of the GNU General Public License version 2 as
8d9110b0bSSrujanaChalla  * published by the Free Software Foundation.
9d9110b0bSSrujanaChalla  */
10d9110b0bSSrujanaChalla 
11d9110b0bSSrujanaChalla #include "otx_cpt_common.h"
12d9110b0bSSrujanaChalla #include "otx_cptpf.h"
13d9110b0bSSrujanaChalla 
14d9110b0bSSrujanaChalla #define DRV_NAME	"octeontx-cpt"
15d9110b0bSSrujanaChalla #define DRV_VERSION	"1.0"
16d9110b0bSSrujanaChalla 
otx_cpt_disable_mbox_interrupts(struct otx_cpt_device * cpt)17d9110b0bSSrujanaChalla static void otx_cpt_disable_mbox_interrupts(struct otx_cpt_device *cpt)
18d9110b0bSSrujanaChalla {
19d9110b0bSSrujanaChalla 	/* Disable mbox(0) interrupts for all VFs */
20d9110b0bSSrujanaChalla 	writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1CX(0));
21d9110b0bSSrujanaChalla }
22d9110b0bSSrujanaChalla 
otx_cpt_enable_mbox_interrupts(struct otx_cpt_device * cpt)23d9110b0bSSrujanaChalla static void otx_cpt_enable_mbox_interrupts(struct otx_cpt_device *cpt)
24d9110b0bSSrujanaChalla {
25d9110b0bSSrujanaChalla 	/* Enable mbox(0) interrupts for all VFs */
26d9110b0bSSrujanaChalla 	writeq(~0ull, cpt->reg_base + OTX_CPT_PF_MBOX_ENA_W1SX(0));
27d9110b0bSSrujanaChalla }
28d9110b0bSSrujanaChalla 
otx_cpt_mbx0_intr_handler(int __always_unused irq,void * cpt)29d9110b0bSSrujanaChalla static irqreturn_t otx_cpt_mbx0_intr_handler(int __always_unused irq,
30d9110b0bSSrujanaChalla 					     void *cpt)
31d9110b0bSSrujanaChalla {
32d9110b0bSSrujanaChalla 	otx_cpt_mbox_intr_handler(cpt, 0);
33d9110b0bSSrujanaChalla 
34d9110b0bSSrujanaChalla 	return IRQ_HANDLED;
35d9110b0bSSrujanaChalla }
36d9110b0bSSrujanaChalla 
otx_cpt_reset(struct otx_cpt_device * cpt)37d9110b0bSSrujanaChalla static void otx_cpt_reset(struct otx_cpt_device *cpt)
38d9110b0bSSrujanaChalla {
39d9110b0bSSrujanaChalla 	writeq(1, cpt->reg_base + OTX_CPT_PF_RESET);
40d9110b0bSSrujanaChalla }
41d9110b0bSSrujanaChalla 
otx_cpt_find_max_enabled_cores(struct otx_cpt_device * cpt)42d9110b0bSSrujanaChalla static void otx_cpt_find_max_enabled_cores(struct otx_cpt_device *cpt)
43d9110b0bSSrujanaChalla {
44d9110b0bSSrujanaChalla 	union otx_cptx_pf_constants pf_cnsts = {0};
45d9110b0bSSrujanaChalla 
46d9110b0bSSrujanaChalla 	pf_cnsts.u = readq(cpt->reg_base + OTX_CPT_PF_CONSTANTS);
47d9110b0bSSrujanaChalla 	cpt->eng_grps.avail.max_se_cnt = pf_cnsts.s.se;
48d9110b0bSSrujanaChalla 	cpt->eng_grps.avail.max_ae_cnt = pf_cnsts.s.ae;
49d9110b0bSSrujanaChalla }
50d9110b0bSSrujanaChalla 
otx_cpt_check_bist_status(struct otx_cpt_device * cpt)51d9110b0bSSrujanaChalla static u32 otx_cpt_check_bist_status(struct otx_cpt_device *cpt)
52d9110b0bSSrujanaChalla {
53d9110b0bSSrujanaChalla 	union otx_cptx_pf_bist_status bist_sts = {0};
54d9110b0bSSrujanaChalla 
55d9110b0bSSrujanaChalla 	bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_BIST_STATUS);
56d9110b0bSSrujanaChalla 	return bist_sts.u;
57d9110b0bSSrujanaChalla }
58d9110b0bSSrujanaChalla 
otx_cpt_check_exe_bist_status(struct otx_cpt_device * cpt)59d9110b0bSSrujanaChalla static u64 otx_cpt_check_exe_bist_status(struct otx_cpt_device *cpt)
60d9110b0bSSrujanaChalla {
61d9110b0bSSrujanaChalla 	union otx_cptx_pf_exe_bist_status bist_sts = {0};
62d9110b0bSSrujanaChalla 
63d9110b0bSSrujanaChalla 	bist_sts.u = readq(cpt->reg_base + OTX_CPT_PF_EXE_BIST_STATUS);
64d9110b0bSSrujanaChalla 	return bist_sts.u;
65d9110b0bSSrujanaChalla }
66d9110b0bSSrujanaChalla 
otx_cpt_device_init(struct otx_cpt_device * cpt)67d9110b0bSSrujanaChalla static int otx_cpt_device_init(struct otx_cpt_device *cpt)
68d9110b0bSSrujanaChalla {
69d9110b0bSSrujanaChalla 	struct device *dev = &cpt->pdev->dev;
70d9110b0bSSrujanaChalla 	u16 sdevid;
71d9110b0bSSrujanaChalla 	u64 bist;
72d9110b0bSSrujanaChalla 
73d9110b0bSSrujanaChalla 	/* Reset the PF when probed first */
74d9110b0bSSrujanaChalla 	otx_cpt_reset(cpt);
75d9110b0bSSrujanaChalla 	mdelay(100);
76d9110b0bSSrujanaChalla 
77d9110b0bSSrujanaChalla 	pci_read_config_word(cpt->pdev, PCI_SUBSYSTEM_ID, &sdevid);
78d9110b0bSSrujanaChalla 
79d9110b0bSSrujanaChalla 	/* Check BIST status */
80d9110b0bSSrujanaChalla 	bist = (u64)otx_cpt_check_bist_status(cpt);
81d9110b0bSSrujanaChalla 	if (bist) {
820a8f5989SChristophe JAILLET 		dev_err(dev, "RAM BIST failed with code 0x%llx\n", bist);
83d9110b0bSSrujanaChalla 		return -ENODEV;
84d9110b0bSSrujanaChalla 	}
85d9110b0bSSrujanaChalla 
86d9110b0bSSrujanaChalla 	bist = otx_cpt_check_exe_bist_status(cpt);
87d9110b0bSSrujanaChalla 	if (bist) {
880a8f5989SChristophe JAILLET 		dev_err(dev, "Engine BIST failed with code 0x%llx\n", bist);
89d9110b0bSSrujanaChalla 		return -ENODEV;
90d9110b0bSSrujanaChalla 	}
91d9110b0bSSrujanaChalla 
92d9110b0bSSrujanaChalla 	/* Get max enabled cores */
93d9110b0bSSrujanaChalla 	otx_cpt_find_max_enabled_cores(cpt);
94d9110b0bSSrujanaChalla 
95d9110b0bSSrujanaChalla 	if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) &&
96d9110b0bSSrujanaChalla 	    (cpt->eng_grps.avail.max_se_cnt == 0)) {
97d9110b0bSSrujanaChalla 		cpt->pf_type = OTX_CPT_AE;
98d9110b0bSSrujanaChalla 	} else if ((sdevid == OTX_CPT_PCI_PF_SUBSYS_ID) &&
99d9110b0bSSrujanaChalla 		   (cpt->eng_grps.avail.max_ae_cnt == 0)) {
100d9110b0bSSrujanaChalla 		cpt->pf_type = OTX_CPT_SE;
101d9110b0bSSrujanaChalla 	}
102d9110b0bSSrujanaChalla 
103d9110b0bSSrujanaChalla 	/* Get max VQs/VFs supported by the device */
104d9110b0bSSrujanaChalla 	cpt->max_vfs = pci_sriov_get_totalvfs(cpt->pdev);
105d9110b0bSSrujanaChalla 
106d9110b0bSSrujanaChalla 	/* Disable all cores */
107d9110b0bSSrujanaChalla 	otx_cpt_disable_all_cores(cpt);
108d9110b0bSSrujanaChalla 
109d9110b0bSSrujanaChalla 	return 0;
110d9110b0bSSrujanaChalla }
111d9110b0bSSrujanaChalla 
otx_cpt_register_interrupts(struct otx_cpt_device * cpt)112d9110b0bSSrujanaChalla static int otx_cpt_register_interrupts(struct otx_cpt_device *cpt)
113d9110b0bSSrujanaChalla {
114d9110b0bSSrujanaChalla 	struct device *dev = &cpt->pdev->dev;
115d9110b0bSSrujanaChalla 	u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT;
116d9110b0bSSrujanaChalla 	u32 num_vec = OTX_CPT_PF_MSIX_VECTORS;
117d9110b0bSSrujanaChalla 	int ret;
118d9110b0bSSrujanaChalla 
119d9110b0bSSrujanaChalla 	/* Enable MSI-X */
120d9110b0bSSrujanaChalla 	ret = pci_alloc_irq_vectors(cpt->pdev, num_vec, num_vec, PCI_IRQ_MSIX);
121d9110b0bSSrujanaChalla 	if (ret < 0) {
122d9110b0bSSrujanaChalla 		dev_err(&cpt->pdev->dev,
123d9110b0bSSrujanaChalla 			"Request for #%d msix vectors failed\n",
124d9110b0bSSrujanaChalla 			num_vec);
125d9110b0bSSrujanaChalla 		return ret;
126d9110b0bSSrujanaChalla 	}
127d9110b0bSSrujanaChalla 
128d9110b0bSSrujanaChalla 	/* Register mailbox interrupt handlers */
129d9110b0bSSrujanaChalla 	ret = request_irq(pci_irq_vector(cpt->pdev,
130d9110b0bSSrujanaChalla 				OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)),
131d9110b0bSSrujanaChalla 				otx_cpt_mbx0_intr_handler, 0, "CPT Mbox0", cpt);
132d9110b0bSSrujanaChalla 	if (ret) {
133d9110b0bSSrujanaChalla 		dev_err(dev, "Request irq failed\n");
134d9110b0bSSrujanaChalla 		pci_free_irq_vectors(cpt->pdev);
135d9110b0bSSrujanaChalla 		return ret;
136d9110b0bSSrujanaChalla 	}
137d9110b0bSSrujanaChalla 	/* Enable mailbox interrupt */
138d9110b0bSSrujanaChalla 	otx_cpt_enable_mbox_interrupts(cpt);
139d9110b0bSSrujanaChalla 	return 0;
140d9110b0bSSrujanaChalla }
141d9110b0bSSrujanaChalla 
otx_cpt_unregister_interrupts(struct otx_cpt_device * cpt)142d9110b0bSSrujanaChalla static void otx_cpt_unregister_interrupts(struct otx_cpt_device *cpt)
143d9110b0bSSrujanaChalla {
144d9110b0bSSrujanaChalla 	u32 mbox_int_idx = OTX_CPT_PF_MBOX_INT;
145d9110b0bSSrujanaChalla 
146d9110b0bSSrujanaChalla 	otx_cpt_disable_mbox_interrupts(cpt);
147d9110b0bSSrujanaChalla 	free_irq(pci_irq_vector(cpt->pdev,
148d9110b0bSSrujanaChalla 				OTX_CPT_PF_INT_VEC_E_MBOXX(mbox_int_idx, 0)),
149d9110b0bSSrujanaChalla 				cpt);
150d9110b0bSSrujanaChalla 	pci_free_irq_vectors(cpt->pdev);
151d9110b0bSSrujanaChalla }
152d9110b0bSSrujanaChalla 
153d9110b0bSSrujanaChalla 
otx_cpt_sriov_configure(struct pci_dev * pdev,int numvfs)154d9110b0bSSrujanaChalla static int otx_cpt_sriov_configure(struct pci_dev *pdev, int numvfs)
155d9110b0bSSrujanaChalla {
156d9110b0bSSrujanaChalla 	struct otx_cpt_device *cpt = pci_get_drvdata(pdev);
157d9110b0bSSrujanaChalla 	int ret = 0;
158d9110b0bSSrujanaChalla 
159d9110b0bSSrujanaChalla 	if (numvfs > cpt->max_vfs)
160d9110b0bSSrujanaChalla 		numvfs = cpt->max_vfs;
161d9110b0bSSrujanaChalla 
162d9110b0bSSrujanaChalla 	if (numvfs > 0) {
163d9110b0bSSrujanaChalla 		ret = otx_cpt_try_create_default_eng_grps(cpt->pdev,
164d9110b0bSSrujanaChalla 							  &cpt->eng_grps,
165d9110b0bSSrujanaChalla 							  cpt->pf_type);
166d9110b0bSSrujanaChalla 		if (ret)
167d9110b0bSSrujanaChalla 			return ret;
168d9110b0bSSrujanaChalla 
169d9110b0bSSrujanaChalla 		cpt->vfs_enabled = numvfs;
170d9110b0bSSrujanaChalla 		ret = pci_enable_sriov(pdev, numvfs);
171d9110b0bSSrujanaChalla 		if (ret) {
172d9110b0bSSrujanaChalla 			cpt->vfs_enabled = 0;
173d9110b0bSSrujanaChalla 			return ret;
174d9110b0bSSrujanaChalla 		}
175d9110b0bSSrujanaChalla 		otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, true);
176d9110b0bSSrujanaChalla 		try_module_get(THIS_MODULE);
177d9110b0bSSrujanaChalla 		ret = numvfs;
178d9110b0bSSrujanaChalla 	} else {
179d9110b0bSSrujanaChalla 		pci_disable_sriov(pdev);
180d9110b0bSSrujanaChalla 		otx_cpt_set_eng_grps_is_rdonly(&cpt->eng_grps, false);
181d9110b0bSSrujanaChalla 		module_put(THIS_MODULE);
182d9110b0bSSrujanaChalla 		cpt->vfs_enabled = 0;
183d9110b0bSSrujanaChalla 	}
184d9110b0bSSrujanaChalla 	dev_notice(&cpt->pdev->dev, "VFs enabled: %d\n", ret);
185d9110b0bSSrujanaChalla 
186d9110b0bSSrujanaChalla 	return ret;
187d9110b0bSSrujanaChalla }
188d9110b0bSSrujanaChalla 
otx_cpt_probe(struct pci_dev * pdev,const struct pci_device_id __always_unused * ent)189d9110b0bSSrujanaChalla static int otx_cpt_probe(struct pci_dev *pdev,
190d9110b0bSSrujanaChalla 			 const struct pci_device_id __always_unused *ent)
191d9110b0bSSrujanaChalla {
192d9110b0bSSrujanaChalla 	struct device *dev = &pdev->dev;
193d9110b0bSSrujanaChalla 	struct otx_cpt_device *cpt;
194d9110b0bSSrujanaChalla 	int err;
195d9110b0bSSrujanaChalla 
196d9110b0bSSrujanaChalla 	cpt = devm_kzalloc(dev, sizeof(*cpt), GFP_KERNEL);
197d9110b0bSSrujanaChalla 	if (!cpt)
198d9110b0bSSrujanaChalla 		return -ENOMEM;
199d9110b0bSSrujanaChalla 
200d9110b0bSSrujanaChalla 	pci_set_drvdata(pdev, cpt);
201d9110b0bSSrujanaChalla 	cpt->pdev = pdev;
202d9110b0bSSrujanaChalla 
203d9110b0bSSrujanaChalla 	err = pci_enable_device(pdev);
204d9110b0bSSrujanaChalla 	if (err) {
205d9110b0bSSrujanaChalla 		dev_err(dev, "Failed to enable PCI device\n");
206d9110b0bSSrujanaChalla 		goto err_clear_drvdata;
207d9110b0bSSrujanaChalla 	}
208d9110b0bSSrujanaChalla 
209d9110b0bSSrujanaChalla 	err = pci_request_regions(pdev, DRV_NAME);
210d9110b0bSSrujanaChalla 	if (err) {
211d9110b0bSSrujanaChalla 		dev_err(dev, "PCI request regions failed 0x%x\n", err);
212d9110b0bSSrujanaChalla 		goto err_disable_device;
213d9110b0bSSrujanaChalla 	}
214d9110b0bSSrujanaChalla 
215*7f6c383bSChristophe JAILLET 	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));
216d9110b0bSSrujanaChalla 	if (err) {
217*7f6c383bSChristophe JAILLET 		dev_err(dev, "Unable to get usable 48-bit DMA configuration\n");
218d9110b0bSSrujanaChalla 		goto err_release_regions;
219d9110b0bSSrujanaChalla 	}
220d9110b0bSSrujanaChalla 
221d9110b0bSSrujanaChalla 	/* MAP PF's configuration registers */
222d9110b0bSSrujanaChalla 	cpt->reg_base = pci_iomap(pdev, OTX_CPT_PF_PCI_CFG_BAR, 0);
223d9110b0bSSrujanaChalla 	if (!cpt->reg_base) {
224d9110b0bSSrujanaChalla 		dev_err(dev, "Cannot map config register space, aborting\n");
225d9110b0bSSrujanaChalla 		err = -ENOMEM;
226d9110b0bSSrujanaChalla 		goto err_release_regions;
227d9110b0bSSrujanaChalla 	}
228d9110b0bSSrujanaChalla 
229d9110b0bSSrujanaChalla 	/* CPT device HW initialization */
230d9110b0bSSrujanaChalla 	err = otx_cpt_device_init(cpt);
231d9110b0bSSrujanaChalla 	if (err)
232d9110b0bSSrujanaChalla 		goto err_unmap_region;
233d9110b0bSSrujanaChalla 
234d9110b0bSSrujanaChalla 	/* Register interrupts */
235d9110b0bSSrujanaChalla 	err = otx_cpt_register_interrupts(cpt);
236d9110b0bSSrujanaChalla 	if (err)
237d9110b0bSSrujanaChalla 		goto err_unmap_region;
238d9110b0bSSrujanaChalla 
239d9110b0bSSrujanaChalla 	/* Initialize engine groups */
240d9110b0bSSrujanaChalla 	err = otx_cpt_init_eng_grps(pdev, &cpt->eng_grps, cpt->pf_type);
241d9110b0bSSrujanaChalla 	if (err)
242d9110b0bSSrujanaChalla 		goto err_unregister_interrupts;
243d9110b0bSSrujanaChalla 
244d9110b0bSSrujanaChalla 	return 0;
245d9110b0bSSrujanaChalla 
246d9110b0bSSrujanaChalla err_unregister_interrupts:
247d9110b0bSSrujanaChalla 	otx_cpt_unregister_interrupts(cpt);
248d9110b0bSSrujanaChalla err_unmap_region:
249d9110b0bSSrujanaChalla 	pci_iounmap(pdev, cpt->reg_base);
250d9110b0bSSrujanaChalla err_release_regions:
251d9110b0bSSrujanaChalla 	pci_release_regions(pdev);
252d9110b0bSSrujanaChalla err_disable_device:
253d9110b0bSSrujanaChalla 	pci_disable_device(pdev);
254d9110b0bSSrujanaChalla err_clear_drvdata:
255d9110b0bSSrujanaChalla 	pci_set_drvdata(pdev, NULL);
256d9110b0bSSrujanaChalla 
257d9110b0bSSrujanaChalla 	return err;
258d9110b0bSSrujanaChalla }
259d9110b0bSSrujanaChalla 
otx_cpt_remove(struct pci_dev * pdev)260d9110b0bSSrujanaChalla static void otx_cpt_remove(struct pci_dev *pdev)
261d9110b0bSSrujanaChalla {
262d9110b0bSSrujanaChalla 	struct otx_cpt_device *cpt = pci_get_drvdata(pdev);
263d9110b0bSSrujanaChalla 
264d9110b0bSSrujanaChalla 	if (!cpt)
265d9110b0bSSrujanaChalla 		return;
266d9110b0bSSrujanaChalla 
267d9110b0bSSrujanaChalla 	/* Disable VFs */
268d9110b0bSSrujanaChalla 	pci_disable_sriov(pdev);
269d9110b0bSSrujanaChalla 	/* Cleanup engine groups */
270d9110b0bSSrujanaChalla 	otx_cpt_cleanup_eng_grps(pdev, &cpt->eng_grps);
271d9110b0bSSrujanaChalla 	/* Disable CPT PF interrupts */
272d9110b0bSSrujanaChalla 	otx_cpt_unregister_interrupts(cpt);
273d9110b0bSSrujanaChalla 	/* Disengage SE and AE cores from all groups */
274d9110b0bSSrujanaChalla 	otx_cpt_disable_all_cores(cpt);
275d9110b0bSSrujanaChalla 	pci_iounmap(pdev, cpt->reg_base);
276d9110b0bSSrujanaChalla 	pci_release_regions(pdev);
277d9110b0bSSrujanaChalla 	pci_disable_device(pdev);
278d9110b0bSSrujanaChalla 	pci_set_drvdata(pdev, NULL);
279d9110b0bSSrujanaChalla }
280d9110b0bSSrujanaChalla 
281d9110b0bSSrujanaChalla /* Supported devices */
282d9110b0bSSrujanaChalla static const struct pci_device_id otx_cpt_id_table[] = {
283d9110b0bSSrujanaChalla 	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX_CPT_PCI_PF_DEVICE_ID) },
284d9110b0bSSrujanaChalla 	{ 0, }  /* end of table */
285d9110b0bSSrujanaChalla };
286d9110b0bSSrujanaChalla 
287d9110b0bSSrujanaChalla static struct pci_driver otx_cpt_pci_driver = {
288d9110b0bSSrujanaChalla 	.name = DRV_NAME,
289d9110b0bSSrujanaChalla 	.id_table = otx_cpt_id_table,
290d9110b0bSSrujanaChalla 	.probe = otx_cpt_probe,
291d9110b0bSSrujanaChalla 	.remove = otx_cpt_remove,
292d9110b0bSSrujanaChalla 	.sriov_configure = otx_cpt_sriov_configure
293d9110b0bSSrujanaChalla };
294d9110b0bSSrujanaChalla 
295d9110b0bSSrujanaChalla module_pci_driver(otx_cpt_pci_driver);
296d9110b0bSSrujanaChalla 
297d9110b0bSSrujanaChalla MODULE_AUTHOR("Marvell International Ltd.");
298d9110b0bSSrujanaChalla MODULE_DESCRIPTION("Marvell OcteonTX CPT Physical Function Driver");
299d9110b0bSSrujanaChalla MODULE_LICENSE("GPL v2");
300d9110b0bSSrujanaChalla MODULE_VERSION(DRV_VERSION);
301d9110b0bSSrujanaChalla MODULE_DEVICE_TABLE(pci, otx_cpt_id_table);
302