117fd7514SLaurent M Coquerel // SPDX-License-Identifier: GPL-2.0-only
217fd7514SLaurent M Coquerel /* Copyright(c) 2025 Intel Corporation */
317fd7514SLaurent M Coquerel #include <linux/array_size.h>
417fd7514SLaurent M Coquerel #include <linux/device.h>
517fd7514SLaurent M Coquerel #include <linux/dma-mapping.h>
617fd7514SLaurent M Coquerel #include <linux/errno.h>
717fd7514SLaurent M Coquerel #include <linux/list.h>
817fd7514SLaurent M Coquerel #include <linux/module.h>
917fd7514SLaurent M Coquerel #include <linux/pci.h>
1017fd7514SLaurent M Coquerel #include <linux/types.h>
1117fd7514SLaurent M Coquerel
1217fd7514SLaurent M Coquerel #include <adf_accel_devices.h>
1317fd7514SLaurent M Coquerel #include <adf_cfg.h>
1417fd7514SLaurent M Coquerel #include <adf_common_drv.h>
1517fd7514SLaurent M Coquerel #include <adf_dbgfs.h>
1617fd7514SLaurent M Coquerel
1717fd7514SLaurent M Coquerel #include "adf_gen6_shared.h"
1817fd7514SLaurent M Coquerel #include "adf_6xxx_hw_data.h"
1917fd7514SLaurent M Coquerel
2017fd7514SLaurent M Coquerel static int bar_map[] = {
2117fd7514SLaurent M Coquerel 0, /* SRAM */
2217fd7514SLaurent M Coquerel 2, /* PMISC */
2317fd7514SLaurent M Coquerel 4, /* ETR */
2417fd7514SLaurent M Coquerel };
2517fd7514SLaurent M Coquerel
adf_device_down(void * accel_dev)2617fd7514SLaurent M Coquerel static void adf_device_down(void *accel_dev)
2717fd7514SLaurent M Coquerel {
2817fd7514SLaurent M Coquerel adf_dev_down(accel_dev);
2917fd7514SLaurent M Coquerel }
3017fd7514SLaurent M Coquerel
adf_dbgfs_cleanup(void * accel_dev)3117fd7514SLaurent M Coquerel static void adf_dbgfs_cleanup(void *accel_dev)
3217fd7514SLaurent M Coquerel {
3317fd7514SLaurent M Coquerel adf_dbgfs_exit(accel_dev);
3417fd7514SLaurent M Coquerel }
3517fd7514SLaurent M Coquerel
adf_cfg_device_remove(void * accel_dev)3617fd7514SLaurent M Coquerel static void adf_cfg_device_remove(void *accel_dev)
3717fd7514SLaurent M Coquerel {
3817fd7514SLaurent M Coquerel adf_cfg_dev_remove(accel_dev);
3917fd7514SLaurent M Coquerel }
4017fd7514SLaurent M Coquerel
adf_cleanup_hw_data(void * accel_dev)4117fd7514SLaurent M Coquerel static void adf_cleanup_hw_data(void *accel_dev)
4217fd7514SLaurent M Coquerel {
4317fd7514SLaurent M Coquerel struct adf_accel_dev *accel_device = accel_dev;
4417fd7514SLaurent M Coquerel
4517fd7514SLaurent M Coquerel if (accel_device->hw_device) {
4617fd7514SLaurent M Coquerel adf_clean_hw_data_6xxx(accel_device->hw_device);
4717fd7514SLaurent M Coquerel accel_device->hw_device = NULL;
4817fd7514SLaurent M Coquerel }
4917fd7514SLaurent M Coquerel }
5017fd7514SLaurent M Coquerel
adf_devmgr_remove(void * accel_dev)5117fd7514SLaurent M Coquerel static void adf_devmgr_remove(void *accel_dev)
5217fd7514SLaurent M Coquerel {
5317fd7514SLaurent M Coquerel adf_devmgr_rm_dev(accel_dev, NULL);
5417fd7514SLaurent M Coquerel }
5517fd7514SLaurent M Coquerel
adf_probe(struct pci_dev * pdev,const struct pci_device_id * ent)5617fd7514SLaurent M Coquerel static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5717fd7514SLaurent M Coquerel {
5817fd7514SLaurent M Coquerel struct adf_accel_pci *accel_pci_dev;
5917fd7514SLaurent M Coquerel struct adf_hw_device_data *hw_data;
6017fd7514SLaurent M Coquerel struct device *dev = &pdev->dev;
6117fd7514SLaurent M Coquerel struct adf_accel_dev *accel_dev;
6217fd7514SLaurent M Coquerel struct adf_bar *bar;
6317fd7514SLaurent M Coquerel unsigned int i;
6417fd7514SLaurent M Coquerel int ret;
6517fd7514SLaurent M Coquerel
6617fd7514SLaurent M Coquerel if (num_possible_nodes() > 1 && dev_to_node(dev) < 0) {
6717fd7514SLaurent M Coquerel /*
6817fd7514SLaurent M Coquerel * If the accelerator is connected to a node with no memory
6917fd7514SLaurent M Coquerel * there is no point in using the accelerator since the remote
7017fd7514SLaurent M Coquerel * memory transaction will be very slow.
7117fd7514SLaurent M Coquerel */
7217fd7514SLaurent M Coquerel return dev_err_probe(dev, -EINVAL, "Invalid NUMA configuration.\n");
7317fd7514SLaurent M Coquerel }
7417fd7514SLaurent M Coquerel
7517fd7514SLaurent M Coquerel accel_dev = devm_kzalloc(dev, sizeof(*accel_dev), GFP_KERNEL);
7617fd7514SLaurent M Coquerel if (!accel_dev)
7717fd7514SLaurent M Coquerel return -ENOMEM;
7817fd7514SLaurent M Coquerel
7917fd7514SLaurent M Coquerel INIT_LIST_HEAD(&accel_dev->crypto_list);
8017fd7514SLaurent M Coquerel INIT_LIST_HEAD(&accel_dev->list);
8117fd7514SLaurent M Coquerel accel_pci_dev = &accel_dev->accel_pci_dev;
8217fd7514SLaurent M Coquerel accel_pci_dev->pci_dev = pdev;
8317fd7514SLaurent M Coquerel accel_dev->owner = THIS_MODULE;
8417fd7514SLaurent M Coquerel
8517fd7514SLaurent M Coquerel hw_data = devm_kzalloc(dev, sizeof(*hw_data), GFP_KERNEL);
8617fd7514SLaurent M Coquerel if (!hw_data)
8717fd7514SLaurent M Coquerel return -ENOMEM;
8817fd7514SLaurent M Coquerel
8917fd7514SLaurent M Coquerel pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid);
9017fd7514SLaurent M Coquerel pci_read_config_dword(pdev, ADF_GEN6_FUSECTL4_OFFSET, &hw_data->fuses[ADF_FUSECTL4]);
9117fd7514SLaurent M Coquerel pci_read_config_dword(pdev, ADF_GEN6_FUSECTL0_OFFSET, &hw_data->fuses[ADF_FUSECTL0]);
9217fd7514SLaurent M Coquerel pci_read_config_dword(pdev, ADF_GEN6_FUSECTL1_OFFSET, &hw_data->fuses[ADF_FUSECTL1]);
9317fd7514SLaurent M Coquerel
9417fd7514SLaurent M Coquerel if (!(hw_data->fuses[ADF_FUSECTL1] & ICP_ACCEL_GEN6_MASK_WCP_WAT_SLICE))
9517fd7514SLaurent M Coquerel return dev_err_probe(dev, -EFAULT, "Wireless mode is not supported.\n");
9617fd7514SLaurent M Coquerel
9717fd7514SLaurent M Coquerel /* Enable PCI device */
9817fd7514SLaurent M Coquerel ret = pcim_enable_device(pdev);
9917fd7514SLaurent M Coquerel if (ret)
10017fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Cannot enable PCI device.\n");
10117fd7514SLaurent M Coquerel
10217fd7514SLaurent M Coquerel ret = adf_devmgr_add_dev(accel_dev, NULL);
10317fd7514SLaurent M Coquerel if (ret)
10417fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Failed to add new accelerator device.\n");
10517fd7514SLaurent M Coquerel
10617fd7514SLaurent M Coquerel ret = devm_add_action_or_reset(dev, adf_devmgr_remove, accel_dev);
10717fd7514SLaurent M Coquerel if (ret)
10817fd7514SLaurent M Coquerel return ret;
10917fd7514SLaurent M Coquerel
11017fd7514SLaurent M Coquerel accel_dev->hw_device = hw_data;
11117fd7514SLaurent M Coquerel adf_init_hw_data_6xxx(accel_dev->hw_device);
11217fd7514SLaurent M Coquerel
11317fd7514SLaurent M Coquerel ret = devm_add_action_or_reset(dev, adf_cleanup_hw_data, accel_dev);
11417fd7514SLaurent M Coquerel if (ret)
11517fd7514SLaurent M Coquerel return ret;
11617fd7514SLaurent M Coquerel
11717fd7514SLaurent M Coquerel /* Get Accelerators and Accelerator Engine masks */
11817fd7514SLaurent M Coquerel hw_data->accel_mask = hw_data->get_accel_mask(hw_data);
11917fd7514SLaurent M Coquerel hw_data->ae_mask = hw_data->get_ae_mask(hw_data);
12017fd7514SLaurent M Coquerel accel_pci_dev->sku = hw_data->get_sku(hw_data);
12117fd7514SLaurent M Coquerel
12217fd7514SLaurent M Coquerel /* If the device has no acceleration engines then ignore it */
12317fd7514SLaurent M Coquerel if (!hw_data->accel_mask || !hw_data->ae_mask ||
12417fd7514SLaurent M Coquerel (~hw_data->ae_mask & ADF_GEN6_ACCELERATORS_MASK)) {
12517fd7514SLaurent M Coquerel ret = -EFAULT;
12617fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "No acceleration units were found.\n");
12717fd7514SLaurent M Coquerel }
12817fd7514SLaurent M Coquerel
12917fd7514SLaurent M Coquerel /* Create device configuration table */
13017fd7514SLaurent M Coquerel ret = adf_cfg_dev_add(accel_dev);
13117fd7514SLaurent M Coquerel if (ret)
13217fd7514SLaurent M Coquerel return ret;
13317fd7514SLaurent M Coquerel
13417fd7514SLaurent M Coquerel ret = devm_add_action_or_reset(dev, adf_cfg_device_remove, accel_dev);
13517fd7514SLaurent M Coquerel if (ret)
13617fd7514SLaurent M Coquerel return ret;
13717fd7514SLaurent M Coquerel
13817fd7514SLaurent M Coquerel /* Set DMA identifier */
13917fd7514SLaurent M Coquerel ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
14017fd7514SLaurent M Coquerel if (ret)
14117fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "No usable DMA configuration.\n");
14217fd7514SLaurent M Coquerel
14317fd7514SLaurent M Coquerel ret = adf_gen6_cfg_dev_init(accel_dev);
14417fd7514SLaurent M Coquerel if (ret)
14517fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Failed to initialize configuration.\n");
14617fd7514SLaurent M Coquerel
14717fd7514SLaurent M Coquerel /* Get accelerator capability mask */
14817fd7514SLaurent M Coquerel hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev);
14917fd7514SLaurent M Coquerel if (!hw_data->accel_capabilities_mask) {
15017fd7514SLaurent M Coquerel ret = -EINVAL;
15117fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Failed to get capabilities mask.\n");
15217fd7514SLaurent M Coquerel }
15317fd7514SLaurent M Coquerel
15417fd7514SLaurent M Coquerel for (i = 0; i < ARRAY_SIZE(bar_map); i++) {
15517fd7514SLaurent M Coquerel bar = &accel_pci_dev->pci_bars[i];
15617fd7514SLaurent M Coquerel
15717fd7514SLaurent M Coquerel /* Map 64-bit PCIe BAR */
15817fd7514SLaurent M Coquerel bar->virt_addr = pcim_iomap_region(pdev, bar_map[i], pci_name(pdev));
15933cd9343SDan Carpenter if (IS_ERR(bar->virt_addr)) {
16033cd9343SDan Carpenter ret = PTR_ERR(bar->virt_addr);
16117fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Failed to ioremap PCI region.\n");
16217fd7514SLaurent M Coquerel }
16317fd7514SLaurent M Coquerel }
16417fd7514SLaurent M Coquerel
16517fd7514SLaurent M Coquerel pci_set_master(pdev);
16617fd7514SLaurent M Coquerel
16717fd7514SLaurent M Coquerel /*
16817fd7514SLaurent M Coquerel * The PCI config space is saved at this point and will be restored
16917fd7514SLaurent M Coquerel * after a Function Level Reset (FLR) as the FLR does not completely
17017fd7514SLaurent M Coquerel * restore it.
17117fd7514SLaurent M Coquerel */
17217fd7514SLaurent M Coquerel ret = pci_save_state(pdev);
17317fd7514SLaurent M Coquerel if (ret)
17417fd7514SLaurent M Coquerel return dev_err_probe(dev, ret, "Failed to save pci state.\n");
17517fd7514SLaurent M Coquerel
176*662c62bbSSuman Kumar Chakraborty accel_dev->ras_errors.enabled = true;
177*662c62bbSSuman Kumar Chakraborty
17817fd7514SLaurent M Coquerel adf_dbgfs_init(accel_dev);
17917fd7514SLaurent M Coquerel
18017fd7514SLaurent M Coquerel ret = devm_add_action_or_reset(dev, adf_dbgfs_cleanup, accel_dev);
18117fd7514SLaurent M Coquerel if (ret)
18217fd7514SLaurent M Coquerel return ret;
18317fd7514SLaurent M Coquerel
18417fd7514SLaurent M Coquerel ret = adf_dev_up(accel_dev, true);
18517fd7514SLaurent M Coquerel if (ret)
18617fd7514SLaurent M Coquerel return ret;
18717fd7514SLaurent M Coquerel
18817fd7514SLaurent M Coquerel ret = devm_add_action_or_reset(dev, adf_device_down, accel_dev);
18917fd7514SLaurent M Coquerel if (ret)
19017fd7514SLaurent M Coquerel return ret;
19117fd7514SLaurent M Coquerel
19217fd7514SLaurent M Coquerel ret = adf_sysfs_init(accel_dev);
19317fd7514SLaurent M Coquerel
19417fd7514SLaurent M Coquerel return ret;
19517fd7514SLaurent M Coquerel }
19617fd7514SLaurent M Coquerel
adf_shutdown(struct pci_dev * pdev)19717fd7514SLaurent M Coquerel static void adf_shutdown(struct pci_dev *pdev)
19817fd7514SLaurent M Coquerel {
19917fd7514SLaurent M Coquerel struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
20017fd7514SLaurent M Coquerel
20117fd7514SLaurent M Coquerel adf_dev_down(accel_dev);
20217fd7514SLaurent M Coquerel }
20317fd7514SLaurent M Coquerel
20417fd7514SLaurent M Coquerel static const struct pci_device_id adf_pci_tbl[] = {
20517fd7514SLaurent M Coquerel { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_6XXX) },
20617fd7514SLaurent M Coquerel { }
20717fd7514SLaurent M Coquerel };
20817fd7514SLaurent M Coquerel MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
20917fd7514SLaurent M Coquerel
21017fd7514SLaurent M Coquerel static struct pci_driver adf_driver = {
21117fd7514SLaurent M Coquerel .id_table = adf_pci_tbl,
21217fd7514SLaurent M Coquerel .name = ADF_6XXX_DEVICE_NAME,
21317fd7514SLaurent M Coquerel .probe = adf_probe,
21417fd7514SLaurent M Coquerel .shutdown = adf_shutdown,
21517fd7514SLaurent M Coquerel .sriov_configure = adf_sriov_configure,
21617fd7514SLaurent M Coquerel .err_handler = &adf_err_handler,
21717fd7514SLaurent M Coquerel };
21817fd7514SLaurent M Coquerel module_pci_driver(adf_driver);
21917fd7514SLaurent M Coquerel
22017fd7514SLaurent M Coquerel MODULE_LICENSE("GPL");
22117fd7514SLaurent M Coquerel MODULE_AUTHOR("Intel");
22217fd7514SLaurent M Coquerel MODULE_FIRMWARE(ADF_6XXX_FW);
22317fd7514SLaurent M Coquerel MODULE_FIRMWARE(ADF_6XXX_MMP);
22417fd7514SLaurent M Coquerel MODULE_DESCRIPTION("Intel(R) QuickAssist Technology for GEN6 Devices");
22517fd7514SLaurent M Coquerel MODULE_SOFTDEP("pre: crypto-intel_qat");
22617fd7514SLaurent M Coquerel MODULE_IMPORT_NS("CRYPTO_QAT");
227