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