Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d724e019 authored by Tony Truong's avatar Tony Truong
Browse files

msm: pcie: move Synopsys MSI support to MSI controller



Remove all Synopsys MSI code in PCIe root complex driver
and call MSI driver to configure and enable the interrupts.

Change-Id: Id7bfef638f08eb266c108e7bb9c752633c3dca0f
Signed-off-by: default avatarTony Truong <truong@codeaurora.org>
parent 3d18c71f
Loading
Loading
Loading
Loading
+4 −304
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/msm_pcie.h>
@@ -175,7 +174,6 @@
#define MAX_RC_NUM (3)
#define MAX_DEVICE_NUM (20)
#define PCIE_TLP_RD_SIZE (0x5)
#define PCIE_MSI_NR_IRQS (256)
#define PCIE_LOG_PAGES (50)
#define PCIE_CONF_SPACE_DW (1024)
#define PCIE_CLEAR (0xdeadbeef)
@@ -184,14 +182,6 @@
#define MSM_PCIE_MAX_RESET (5)
#define MSM_PCIE_MAX_PIPE_RESET (1)

#define MSM_PCIE_MSI_PHY (0xa0000000)
#define PCIE20_MSI_CTRL_ADDR (0x820)
#define PCIE20_MSI_CTRL_UPPER_ADDR (0x824)
#define PCIE20_MSI_CTRL_INTR_EN (0x828)
#define PCIE20_MSI_CTRL_INTR_MASK (0x82c)
#define PCIE20_MSI_CTRL_INTR_STATUS (0x830)
#define PCIE20_MSI_CTRL_MAX (8)

/* Each tick is 19.2 MHz */
#define L1SS_TIMEOUT_US_TO_TICKS(x) (x * 192 / 10)
#define L1SS_TIMEOUT_US (100000)
@@ -286,7 +276,6 @@ enum msm_pcie_res {
};

enum msm_pcie_irq {
	MSM_PCIE_INT_MSI,
	MSM_PCIE_INT_A,
	MSM_PCIE_INT_B,
	MSM_PCIE_INT_C,
@@ -685,8 +674,6 @@ struct msm_pcie_dev_t {
	struct mutex clk_lock;

	struct irq_domain *irq_domain;
	DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_NR_IRQS);
	bool use_msi;

	enum msm_pcie_link_status link_status;
	bool user_suspend;
@@ -997,7 +984,6 @@ static const struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {

/* irqs */
static const struct msm_pcie_irq_info_t msm_pcie_irq_info[MSM_PCIE_MAX_IRQ] = {
	{"int_msi", 0},
	{"int_a", 0},
	{"int_b", 0},
	{"int_c", 0},
@@ -1301,8 +1287,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
		? "enabled" : "disabled");
	PCIE_DBG_FS(dev, "cfg_access is %s allowed\n",
		dev->cfg_access ? "" : "not");
	PCIE_DBG_FS(dev, "use_msi is %d\n",
		dev->use_msi);
	PCIE_DBG_FS(dev, "use_pinctrl is %d\n",
		dev->use_pinctrl);
	PCIE_DBG_FS(dev, "use_19p2mhz_aux_clk is %d\n",
@@ -3556,24 +3540,6 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
	}
}

static void msm_pcie_config_msi_controller(struct msm_pcie_dev_t *dev)
{
	int i;

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);

	/* program MSI controller and enable all interrupts */
	writel_relaxed(MSM_PCIE_MSI_PHY, dev->dm_core + PCIE20_MSI_CTRL_ADDR);
	writel_relaxed(0, dev->dm_core + PCIE20_MSI_CTRL_UPPER_ADDR);

	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++)
		writel_relaxed(~0, dev->dm_core +
			       PCIE20_MSI_CTRL_INTR_EN + (i * 12));

	/* ensure that hardware is configured before proceeding */
	wmb();
}

static int msm_pcie_get_clk(struct msm_pcie_dev_t *pcie_dev)
{
	int i, cnt, ret;
@@ -4265,23 +4231,11 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev)
	writel_relaxed(dev->slv_addr_space_size, dev->parf +
		PCIE20_PARF_SLV_ADDR_SPACE_SIZE);

	if (dev->use_msi) {
		PCIE_DBG(dev, "RC%d: enable WR halt.\n", dev->rc_idx);
	val = dev->wr_halt_size ? dev->wr_halt_size :
			readl_relaxed(dev->parf +
				PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);

		msm_pcie_write_reg(dev->parf,
			PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT,
		readl_relaxed(dev->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
	msm_pcie_write_reg(dev->parf, PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT,
				BIT(31) | val);

		PCIE_DBG(dev,
			"RC%d: PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT: 0x%x.\n",
			dev->rc_idx,
			readl_relaxed(dev->parf +
				PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT));
	}

	/* init PCIe PHY */
	ret = pcie_phy_init(dev);
	if (ret)
@@ -4347,9 +4301,6 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev)
		goto link_fail;
	}

	if (!IS_ENABLED(CONFIG_PCI_MSM_MSI))
		msm_pcie_config_msi_controller(dev);

	if (dev->enumerated)
		msm_pcie_config_link_pm(dev, true);

@@ -5109,39 +5060,6 @@ static irqreturn_t handle_linkdown_irq(int irq, void *data)
	return IRQ_HANDLED;
}

static irqreturn_t handle_msi_irq(int irq, void *data)
{
	int i, j;
	unsigned long val;
	struct msm_pcie_dev_t *dev = data;
	void __iomem *ctrl_status;

	PCIE_DUMP(dev, "irq: %d\n", irq);

	/*
	 * check for set bits, clear it by setting that bit
	 * and trigger corresponding irq
	 */
	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) {
		ctrl_status = dev->dm_core +
				PCIE20_MSI_CTRL_INTR_STATUS + (i * 12);

		val = readl_relaxed(ctrl_status);
		while (val) {
			j = find_first_bit(&val, 32);
			writel_relaxed(BIT(j), ctrl_status);
			/* ensure that interrupt is cleared (acked) */
			wmb();
			generic_handle_irq(
			   irq_find_mapping(dev->irq_domain, (j + (32*i)))
			   );
			val = readl_relaxed(ctrl_status);
		}
	}

	return IRQ_HANDLED;
}

static irqreturn_t handle_global_irq(int irq, void *data)
{
	int i;
@@ -5205,192 +5123,9 @@ static irqreturn_t handle_global_irq(int irq, void *data)
	return IRQ_HANDLED;
}

static void msm_pcie_destroy_irq(struct msi_desc *entry, unsigned int irq)
{
	int pos;
	struct msm_pcie_dev_t *dev;
	struct pci_dev *pdev = msi_desc_to_pci_dev(entry);

	if (!pdev) {
		pr_err("PCIe: pci device is null. IRQ:%d\n", irq);
		return;
	}

	dev = PCIE_BUS_PRIV_DATA(pdev->bus);
	if (!dev) {
		pr_err("PCIe: could not find RC. IRQ:%d\n", irq);
		return;
	}

	PCIE_DBG(dev, "destroy default MSI irq %d\n", irq);
	pos = irq - irq_find_mapping(dev->irq_domain, 0);

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);

	PCIE_DBG(dev, "Before clear_bit pos:%d msi_irq_in_use:%ld\n",
		pos, *dev->msi_irq_in_use);
	clear_bit(pos, dev->msi_irq_in_use);
	PCIE_DBG(dev, "After clear_bit pos:%d msi_irq_in_use:%ld\n",
		pos, *dev->msi_irq_in_use);
}

/* hookup to linux pci msi framework */
void arch_teardown_msi_irq(unsigned int irq)
{
	struct msi_desc *entry = irq_get_msi_desc(irq);

	PCIE_GEN_DBG("irq %d deallocated\n", irq);

	if (entry)
		msm_pcie_destroy_irq(entry, irq);
}

void arch_teardown_msi_irqs(struct pci_dev *dev)
{
	struct msi_desc *entry;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);

	PCIE_DBG(pcie_dev, "RC:%d EP: vendor_id:0x%x device_id:0x%x\n",
		pcie_dev->rc_idx, dev->vendor, dev->device);

	pcie_dev->use_msi = false;

	list_for_each_entry(entry, &dev->dev.msi_list, list) {
		int i, nvec;

		if (entry->irq == 0)
			continue;
		nvec = 1 << entry->msi_attrib.multiple;
		for (i = 0; i < nvec; i++)
			msm_pcie_destroy_irq(entry, entry->irq + i);
	}
}

static void msm_pcie_msi_nop(struct irq_data *d)
{
}

static struct irq_chip pcie_msi_chip = {
	.name = "msm-pcie-msi",
	.irq_ack = msm_pcie_msi_nop,
	.irq_enable = unmask_msi_irq,
	.irq_disable = mask_msi_irq,
	.irq_mask = mask_msi_irq,
	.irq_unmask = unmask_msi_irq,
};

static int msm_pcie_create_irq(struct msm_pcie_dev_t *dev)
{
	int irq, pos;

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);

again:
	pos = find_first_zero_bit(dev->msi_irq_in_use, PCIE_MSI_NR_IRQS);

	if (pos >= PCIE_MSI_NR_IRQS)
		return -ENOSPC;

	PCIE_DBG(dev, "pos:%d msi_irq_in_use:%ld\n", pos, *dev->msi_irq_in_use);

	if (test_and_set_bit(pos, dev->msi_irq_in_use))
		goto again;
	else
		PCIE_DBG(dev, "test_and_set_bit is successful pos=%d\n", pos);

	irq = irq_create_mapping(dev->irq_domain, pos);
	if (!irq)
		return -EINVAL;

	return irq;
}

static int arch_setup_msi_irq_default(struct pci_dev *pdev,
		struct msi_desc *desc, int nvec)
{
	int irq;
	struct msi_msg msg;
	struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev->bus);

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);

	irq = msm_pcie_create_irq(dev);

	PCIE_DBG(dev, "IRQ %d is allocated.\n", irq);

	if (irq < 0)
		return irq;

	PCIE_DBG(dev, "irq %d allocated\n", irq);

	irq_set_chip_data(irq, pdev);
	irq_set_msi_desc(irq, desc);

	/* write msi vector and data */
	msg.address_hi = 0;
	msg.address_lo = MSM_PCIE_MSI_PHY;
	msg.data = irq - irq_find_mapping(dev->irq_domain, 0);
	write_msi_msg(irq, &msg);

	return 0;
}

int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
	struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev->bus);

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);

	return arch_setup_msi_irq_default(pdev, desc, 1);
}

int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
	struct msi_desc *entry;
	int ret;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);

	PCIE_DBG(pcie_dev, "RC%d\n", pcie_dev->rc_idx);

	if (type != PCI_CAP_ID_MSI || nvec > 32)
		return -ENOSPC;

	PCIE_DBG(pcie_dev, "nvec = %d\n", nvec);

	list_for_each_entry(entry, &dev->dev.msi_list, list) {
		entry->msi_attrib.multiple =
			__ilog2_u32(__roundup_pow_of_two(nvec));

		ret = arch_setup_msi_irq_default(dev, entry, nvec);

		PCIE_DBG(pcie_dev, "ret from msi_irq: %d\n", ret);

		if (ret < 0)
			return ret;
		if (ret > 0)
			return -ENOSPC;
	}

	pcie_dev->use_msi = true;

	return 0;
}

static int msm_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
	   irq_hw_number_t hwirq)
{
	irq_set_chip_and_handler (irq, &pcie_msi_chip, handle_simple_irq);
	return 0;
}

static const struct irq_domain_ops msm_pcie_msi_ops = {
	.map = msm_pcie_msi_map,
};

static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
{
	int rc;
	int msi_start =  0;
	struct device *pdev = &dev->pdev->dev;

	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);
@@ -5400,22 +5135,6 @@ static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
	else
		wakeup_source_init(&dev->ws, "RC0 pcie_wakeup_source");

	/* register handler for physical MSI interrupt line */
	if (dev->irq[MSM_PCIE_INT_MSI].num) {
		rc = devm_request_irq(pdev,
			dev->irq[MSM_PCIE_INT_MSI].num,
			handle_msi_irq,
			IRQF_TRIGGER_RISING,
			dev->irq[MSM_PCIE_INT_MSI].name,
			dev);
		if (rc) {
			PCIE_ERR(dev,
				"PCIe: RC%d: Unable to request MSI interrupt\n",
				dev->rc_idx);
			return rc;
		}
	}

	if (dev->irq[MSM_PCIE_INT_GLOBAL_INT].num) {
		rc = devm_request_irq(pdev,
				dev->irq[MSM_PCIE_INT_GLOBAL_INT].num,
@@ -5455,25 +5174,6 @@ static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
		}
	}

	/* Create a virtual domain of interrupts */
	if (!IS_ENABLED(CONFIG_PCI_MSM_MSI)) {
		dev->irq_domain = irq_domain_add_linear(dev->pdev->dev.of_node,
			PCIE_MSI_NR_IRQS, &msm_pcie_msi_ops, dev);

		if (!dev->irq_domain) {
			PCIE_ERR(dev,
				"PCIe: RC%d: Unable to initialize irq domain\n",
				dev->rc_idx);

			if (dev->wake_n)
				disable_irq(dev->wake_n);

			return PTR_ERR(dev->irq_domain);
		}

		msi_start = irq_create_mapping(dev->irq_domain, 0);
	}

	return 0;
}