static int thunderx_l2c_probe()

in thunderx_edac.c [1945:2079]


static int thunderx_l2c_probe(struct pci_dev *pdev,
			      const struct pci_device_id *id)
{
	struct thunderx_l2c *l2c;
	struct edac_device_ctl_info *edac_dev;
	struct debugfs_entry **l2c_devattr;
	size_t dfs_entries;
	irqreturn_t (*thunderx_l2c_isr)(int, void *) = NULL;
	char name[32];
	const char *fmt;
	u64 reg_en_offs, reg_en_mask;
	int idx;
	int ret;

	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_l2c");
	if (ret) {
		dev_err(&pdev->dev, "Cannot map PCI resources: %d\n", ret);
		return ret;
	}

	switch (pdev->device) {
	case PCI_DEVICE_ID_THUNDER_L2C_TAD:
		thunderx_l2c_isr = thunderx_l2c_tad_isr;
		l2c_devattr = l2c_tad_dfs_ents;
		dfs_entries = ARRAY_SIZE(l2c_tad_dfs_ents);
		fmt = "L2C-TAD%d";
		reg_en_offs = L2C_TAD_INT_ENA_W1S;
		reg_en_mask = L2C_TAD_INT_ENA_ALL;
		break;
	case PCI_DEVICE_ID_THUNDER_L2C_CBC:
		thunderx_l2c_isr = thunderx_l2c_cbc_isr;
		l2c_devattr = l2c_cbc_dfs_ents;
		dfs_entries = ARRAY_SIZE(l2c_cbc_dfs_ents);
		fmt = "L2C-CBC%d";
		reg_en_offs = L2C_CBC_INT_ENA_W1S;
		reg_en_mask = L2C_CBC_INT_ENA_ALL;
		break;
	case PCI_DEVICE_ID_THUNDER_L2C_MCI:
		thunderx_l2c_isr = thunderx_l2c_mci_isr;
		l2c_devattr = l2c_mci_dfs_ents;
		dfs_entries = ARRAY_SIZE(l2c_mci_dfs_ents);
		fmt = "L2C-MCI%d";
		reg_en_offs = L2C_MCI_INT_ENA_W1S;
		reg_en_mask = L2C_MCI_INT_ENA_ALL;
		break;
	default:
		//Should never ever get here
		dev_err(&pdev->dev, "Unsupported PCI device: %04x\n",
			pdev->device);
		return -EINVAL;
	}

	idx = edac_device_alloc_index();
	snprintf(name, sizeof(name), fmt, idx);

	edac_dev = edac_device_alloc_ctl_info(sizeof(struct thunderx_l2c),
					      name, 1, "L2C", 1, 0,
					      NULL, 0, idx);
	if (!edac_dev) {
		dev_err(&pdev->dev, "Cannot allocate EDAC device\n");
		return -ENOMEM;
	}

	l2c = edac_dev->pvt_info;
	l2c->edac_dev = edac_dev;

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

	l2c->pdev = pdev;

	l2c->ring_head = 0;
	l2c->ring_tail = 0;

	l2c->msix_ent.entry = 0;
	l2c->msix_ent.vector = 0;

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

	ret = devm_request_threaded_irq(&pdev->dev, l2c->msix_ent.vector,
					thunderx_l2c_isr,
					thunderx_l2c_threaded_isr,
					0, "[EDAC] ThunderX L2C",
					&l2c->msix_ent);
	if (ret)
		goto err_free;

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

	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)) {
		l2c->debugfs = edac_debugfs_create_dir(pdev->dev.kobj.name);

		ret = thunderx_create_debugfs_nodes(l2c->debugfs, l2c_devattr,
					      l2c, dfs_entries);

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

	pci_set_drvdata(pdev, edac_dev);

	writeq(reg_en_mask, l2c->regs + reg_en_offs);

	return 0;

err_free:
	edac_device_free_ctl_info(edac_dev);

	return ret;
}