static int thunderx_ocx_probe()

in thunderx_edac.c [1342:1471]


static int thunderx_ocx_probe(struct pci_dev *pdev,
			      const struct pci_device_id *id)
{
	struct thunderx_ocx *ocx;
	struct edac_device_ctl_info *edac_dev;
	char name[32];
	int idx;
	int i;
	int ret;
	u64 reg;

	ret = pcim_enable_device(pdev);
	if (ret) {
		dev_err(&pdev->dev, "Cannot enable PCI device: %d\n", ret);
		return ret;
	}

	ret = pcim_iomap_regions(pdev, BIT(0), "thunderx_ocx");
	if (ret) {
		dev_err(&pdev->dev, "Cannot map PCI resources: %d\n", ret);
		return ret;
	}

	idx = edac_device_alloc_index();
	snprintf(name, sizeof(name), "OCX%d", idx);
	edac_dev = edac_device_alloc_ctl_info(sizeof(struct thunderx_ocx),
					      name, 1, "CCPI", 1,
					      0, NULL, 0, idx);
	if (!edac_dev) {
		dev_err(&pdev->dev, "Cannot allocate EDAC device\n");
		return -ENOMEM;
	}
	ocx = edac_dev->pvt_info;
	ocx->edac_dev = edac_dev;
	ocx->com_ring_head = 0;
	ocx->com_ring_tail = 0;
	ocx->link_ring_head = 0;
	ocx->link_ring_tail = 0;

	ocx->regs = pcim_iomap_table(pdev)[0];
	if (!ocx->regs) {
		dev_err(&pdev->dev, "Cannot map PCI resources\n");
		ret = -ENODEV;
		goto err_free;
	}

	ocx->pdev = pdev;

	for (i = 0; i < OCX_INTS; i++) {
		ocx->msix_ent[i].entry = i;
		ocx->msix_ent[i].vector = 0;
	}

	ret = pci_enable_msix_exact(pdev, ocx->msix_ent, OCX_INTS);
	if (ret) {
		dev_err(&pdev->dev, "Cannot enable interrupt: %d\n", ret);
		goto err_free;
	}

	for (i = 0; i < OCX_INTS; i++) {
		ret = devm_request_threaded_irq(&pdev->dev,
						ocx->msix_ent[i].vector,
						(i == 3) ?
						 thunderx_ocx_com_isr :
						 thunderx_ocx_lnk_isr,
						(i == 3) ?
						 thunderx_ocx_com_threaded_isr :
						 thunderx_ocx_lnk_threaded_isr,
						0, "[EDAC] ThunderX OCX",
						&ocx->msix_ent[i]);
		if (ret)
			goto err_free;
	}

	edac_dev->dev = &pdev->dev;
	edac_dev->dev_name = dev_name(&pdev->dev);
	edac_dev->mod_name = "thunderx-ocx";
	edac_dev->ctl_name = "thunderx-ocx";

	ret = edac_device_add_device(edac_dev);
	if (ret) {
		dev_err(&pdev->dev, "Cannot add EDAC device: %d\n", ret);
		goto err_free;
	}

	if (IS_ENABLED(CONFIG_EDAC_DEBUG)) {
		ocx->debugfs = edac_debugfs_create_dir(pdev->dev.kobj.name);

		ret = thunderx_create_debugfs_nodes(ocx->debugfs,
						    ocx_dfs_ents,
						    ocx,
						    ARRAY_SIZE(ocx_dfs_ents));
		if (ret != ARRAY_SIZE(ocx_dfs_ents)) {
			dev_warn(&pdev->dev, "Error creating debugfs entries: %d%s\n",
				 ret, ret >= 0 ? " created" : "");
		}
	}

	pci_set_drvdata(pdev, edac_dev);

	thunderx_ocx_clearstats(ocx);

	for (i = 0; i < OCX_RX_LANES; i++) {
		writeq(OCX_LNE_INT_ENA_ALL,
		       ocx->regs + OCX_LNE_INT_EN(i));

		reg = readq(ocx->regs + OCX_LNE_INT(i));
		writeq(reg, ocx->regs + OCX_LNE_INT(i));

	}

	for (i = 0; i < OCX_LINK_INTS; i++) {
		reg = readq(ocx->regs + OCX_COM_LINKX_INT(i));
		writeq(reg, ocx->regs + OCX_COM_LINKX_INT(i));

		writeq(OCX_COM_LINKX_INT_ENA_ALL,
		       ocx->regs + OCX_COM_LINKX_INT_ENA_W1S(i));
	}

	reg = readq(ocx->regs + OCX_COM_INT);
	writeq(reg, ocx->regs + OCX_COM_INT);

	writeq(OCX_COM_INT_ENA_ALL, ocx->regs + OCX_COM_INT_ENA_W1S);

	return 0;
err_free:
	edac_device_free_ctl_info(edac_dev);

	return ret;
}