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

Commit 3190ca6f authored by Yan He's avatar Yan He
Browse files

msm: pcie: Add support for two RCs



Add the support for two PCIe Root Complexes (RCs) in PCIe driver.
Two RCs have the same bus number but are distinguished by
different domain numbers. Add the rc index number to the msm PCIe
device data structure so that rc index number is not explicit as a
parameter of functions. The enumeration of RC1 can happen either
during bootup or after bootup when WAKE GPIO is asserted by
Endpoint. Thus, add the support to enumerate the device based on
WAKE IRQ as well. The PCIe logging is also updated to support two
RCs.

Change-Id: I7fa46400166c40bdf9e73a1507a559a9526d8aac
Signed-off-by: default avatarYan He <yanhe@codeaurora.org>
parent a656c074
Loading
Loading
Loading
Loading
+214 −245
Original line number Diff line number Diff line
@@ -216,9 +216,9 @@ static void msm_pcie_write_mask(void __iomem *addr,
	wmb();  /* ensure data is written to hardware register */
}

static int msm_pcie_is_link_up(u32 rc_idx)
static int msm_pcie_is_link_up(struct msm_pcie_dev_t *dev)
{
	return readl_relaxed(msm_pcie_dev[rc_idx].dm_core +
	return readl_relaxed(dev->dm_core +
			PCIE20_CAP_LINKCTRLSTATUS) & BIT(29);
}

@@ -233,6 +233,16 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
	u32 rc_idx;
	int rv = 0;

	dev = ((struct msm_pcie_dev_t *)
		(((struct pci_sys_data *)bus->sysdata)->private_data));

	if (!dev) {
		pr_err("PCIe: No device found for this bus.\n");
		*val = ~0;
		rv = PCIBIOS_DEVICE_NOT_FOUND;
		goto out;
	}

	/* Do the bus->number based access control since we don't support
	   ECAM mechanism */

@@ -240,18 +250,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
	case 0:
		rc = true;
	case 1:
		if (pcie_drv.rc_expected > 1)
			rc_idx = 0;
		else
			rc_idx = pcie_drv.current_rc;
		break;
	case 2:
		rc = true;
	case 3:
		if (pcie_drv.rc_expected > 1)
			rc_idx = 1;
		else
			rc_idx = pcie_drv.current_rc;
		rc_idx = dev->rc_idx;
		break;
	default:
		pr_err("PCIe: unsupported bus number.\n");
@@ -260,32 +259,29 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
		goto out;
	}

	dev = &msm_pcie_dev[rc_idx];

	if ((bus->number > MAX_BUS_NUM) || (devfn != 0)) {
		PCIE_DBG("invalid %s - bus %d devfn %d\n",
		PCIE_DBG("RC%d invalid %s - bus %d devfn %d\n", rc_idx,
			 (oper == RD) ? "rd" : "wr", bus->number, devfn);
		*val = ~0;
		rv = PCIBIOS_DEVICE_NOT_FOUND;
		goto out;
	}

	spin_lock_irqsave(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	spin_lock_irqsave(&dev->cfg_lock, dev->irqsave_flags);

	if (!msm_pcie_dev[rc_idx].cfg_access) {
		PCIE_DBG("access denied for %d:0x%02x + 0x%04x[%d]\n",
			 bus->number, devfn, where, size);
	if (!dev->cfg_access) {
		PCIE_DBG("Access denied for RC%d %d:0x%02x + 0x%04x[%d]\n",
			rc_idx, bus->number, devfn, where, size);
		*val = ~0;
		rv = PCIBIOS_DEVICE_NOT_FOUND;
		goto unlock;
	}

	/* check if the link is up for endpoint */
	if (((bus->number == 1) || (bus->number == 3))
		&& (!msm_pcie_is_link_up(rc_idx))) {
			pr_err("%s fail, link down - bus %d devfn %d\n",
				(oper == RD) ? "rd" : "wr", bus->number, devfn);
	if (!rc && !msm_pcie_is_link_up(dev)) {
			pr_err("RC%d %s fail, link down - bus %d devfn %d\n",
				rc_idx, (oper == RD) ? "rd" : "wr",
				bus->number, devfn);
			*val = ~0;
			rv = PCIBIOS_DEVICE_NOT_FOUND;
			goto unlock;
@@ -300,8 +296,8 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,

	if (oper == RD) {
		*val = ((rd_val & mask) >> (8 * byte_offset));
		PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
			bus->number, devfn, where, size, *val, rd_val);
		PCIE_DBG("RC%d %d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
			rc_idx, bus->number, devfn, where, size, *val, rd_val);
	} else {
		wr_val = (rd_val & ~mask) |
				((*val << (8 * byte_offset)) & mask);
@@ -309,13 +305,13 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
		wmb(); /* ensure config data is written to hardware register */

		PCIE_DBG(
			"%d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n",
			bus->number, devfn, where, size, wr_val, rd_val, *val);
			"RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n",
			rc_idx, bus->number, devfn, where, size,
			wr_val, rd_val, *val);
	}

unlock:
	spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	spin_unlock_irqrestore(&dev->cfg_lock, dev->irqsave_flags);
out:
	return rv;
}
@@ -344,15 +340,15 @@ static struct pci_ops msm_pcie_ops = {
	.write = msm_pcie_wr_conf,
};

static int msm_pcie_gpio_init(u32 rc_idx)
static int msm_pcie_gpio_init(struct msm_pcie_dev_t *dev)
{
	int rc, i;
	struct msm_pcie_gpio_info_t *info;

	PCIE_DBG("\n");

	for (i = 0; i < msm_pcie_dev[rc_idx].gpio_n; i++) {
		info = &msm_pcie_dev[rc_idx].gpio[i];
	for (i = 0; i < dev->gpio_n; i++) {
		info = &dev->gpio[i];

		if (!info->num)
			continue;
@@ -377,20 +373,20 @@ static int msm_pcie_gpio_init(u32 rc_idx)

	if (rc)
		while (i--)
			gpio_free(msm_pcie_dev[rc_idx].gpio[i].num);
			gpio_free(dev->gpio[i].num);

	return rc;
}

static void msm_pcie_gpio_deinit(u32 rc_idx)
static void msm_pcie_gpio_deinit(struct msm_pcie_dev_t *dev)
{
	int i;

	for (i = 0; i < msm_pcie_dev[rc_idx].gpio_n; i++)
		gpio_free(msm_pcie_dev[rc_idx].gpio[i].num);
	for (i = 0; i < dev->gpio_n; i++)
		gpio_free(dev->gpio[i].num);
}

static int msm_pcie_vreg_init(u32 rc_idx, struct device *dev)
int msm_pcie_vreg_init(struct msm_pcie_dev_t *dev)
{
	int i, rc = 0;
	struct regulator *vreg;
@@ -398,15 +394,8 @@ static int msm_pcie_vreg_init(u32 rc_idx, struct device *dev)

	PCIE_DBG("\n");

	if (pcie_drv.vreg_on) {
		PCIE_DBG("Vreg has been turned on.\n");
		return rc;
	} else {
		pcie_drv.vreg_on = true;
	}

	for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
		info = &msm_pcie_dev[rc_idx].vreg[i];
		info = &dev->vreg[i];
		vreg = info->hdl;

		if (!vreg)
@@ -441,61 +430,42 @@ static int msm_pcie_vreg_init(u32 rc_idx, struct device *dev)

	if (rc)
		while (i--) {
			struct regulator *hdl =
				msm_pcie_dev[rc_idx].vreg[i].hdl;
			struct regulator *hdl = dev->vreg[i].hdl;
			if (hdl)
				regulator_disable(hdl);
		}

	if (rc)
		pcie_drv.vreg_on = false;

	return rc;
}

static void msm_pcie_vreg_deinit(u32 rc_idx)
static void msm_pcie_vreg_deinit(struct msm_pcie_dev_t *dev)
{
	int i;

	if (pcie_drv.vreg_on)
		pcie_drv.vreg_on = false;
	else {
		PCIE_DBG("Vreg has been turned off\n");
		return;
	}

	for (i = MSM_PCIE_MAX_VREG - 1; i >= 0; i--) {
		if (msm_pcie_dev[rc_idx].vreg[i].hdl) {
		if (dev->vreg[i].hdl) {
			PCIE_DBG("Vreg %s is being disabled\n",
				msm_pcie_dev[rc_idx].vreg[i].name);
			regulator_disable(msm_pcie_dev[rc_idx].vreg[i].hdl);
				dev->vreg[i].name);
			regulator_disable(dev->vreg[i].hdl);
		}
	}
}

static int msm_pcie_clk_init(u32 rc_idx, struct device *dev)
static int msm_pcie_clk_init(struct msm_pcie_dev_t *dev)
{
	int i, rc = 0;
	struct msm_pcie_clk_info_t *info;

	PCIE_DBG("\n");

	if (dev) {
		PCIE_DBG("dev name:%s\n", dev_name(dev));
	} else {
		pr_err("PCIe: dev is NULL\n");
		return -ENODEV;
	}

	rc = regulator_enable(msm_pcie_dev[rc_idx].gdsc);
	rc = regulator_enable(dev->gdsc);

	if (rc) {
		pr_err("PCIe: fail to enable GDSC for RC %d\n", rc_idx);
		pr_err("PCIe: fail to enable GDSC for RC %s\n",
			dev->pdev->name);
		return rc;
	}

	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
		info = &msm_pcie_dev[rc_idx].clk[i];
		info = &dev->clk[i];

		if (!info->hdl)
			continue;
@@ -520,44 +490,35 @@ static int msm_pcie_clk_init(u32 rc_idx, struct device *dev)
	if (rc) {
		PCIE_DBG("disable clocks for error handling\n");
		while (i--) {
			struct clk *hdl = msm_pcie_dev[rc_idx].clk[i].hdl;
			struct clk *hdl = dev->clk[i].hdl;
			if (hdl)
				clk_disable_unprepare(hdl);
		}

		regulator_disable(msm_pcie_dev[rc_idx].gdsc);
		regulator_disable(dev->gdsc);
	}

	return rc;
}

static void msm_pcie_clk_deinit(u32 rc_idx)
static void msm_pcie_clk_deinit(struct msm_pcie_dev_t *dev)
{
	int i;

	for (i = 0; i < MSM_PCIE_MAX_CLK; i++)
		if (msm_pcie_dev[rc_idx].clk[i].hdl)
			clk_disable_unprepare(msm_pcie_dev[rc_idx].clk[i].hdl);
		if (dev->clk[i].hdl)
			clk_disable_unprepare(dev->clk[i].hdl);

	regulator_disable(msm_pcie_dev[rc_idx].gdsc);
	regulator_disable(dev->gdsc);
}

static int msm_pcie_pipe_clk_init(u32 rc_idx, struct device *dev)
static int msm_pcie_pipe_clk_init(struct msm_pcie_dev_t *dev)
{
	int i, rc = 0;
	struct msm_pcie_clk_info_t *info;

	PCIE_DBG("\n");

	if (dev) {
		PCIE_DBG("dev name:%s\n", dev_name(dev));
	} else {
		pr_err("PCIe: dev is NULL\n");
		return -ENODEV;
	}

	for (i = 0; i < MSM_PCIE_MAX_PIPE_CLK; i++) {
		info = &msm_pcie_dev[rc_idx].pipeclk[i];
		info = &dev->pipeclk[i];

		if (!info->hdl)
			continue;
@@ -584,28 +545,26 @@ static int msm_pcie_pipe_clk_init(u32 rc_idx, struct device *dev)
	if (rc) {
		PCIE_DBG("disable pipe clocks for error handling\n");
		while (i--)
			if (msm_pcie_dev[rc_idx].pipeclk[i].hdl)
				clk_disable_unprepare(
					msm_pcie_dev[rc_idx].pipeclk[i].hdl);
			if (dev->pipeclk[i].hdl)
				clk_disable_unprepare(dev->pipeclk[i].hdl);
	}

	return rc;
}

static void msm_pcie_pipe_clk_deinit(u32 rc_idx)
static void msm_pcie_pipe_clk_deinit(struct msm_pcie_dev_t *dev)
{
	int i;

	for (i = 0; i < MSM_PCIE_MAX_PIPE_CLK; i++)
		if (msm_pcie_dev[rc_idx].pipeclk[i].hdl)
		if (dev->pipeclk[i].hdl)
			clk_disable_unprepare(
				msm_pcie_dev[rc_idx].pipeclk[i].hdl);
				dev->pipeclk[i].hdl);
}


static void msm_pcie_config_controller(u32 rc_idx)
static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
{
	struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx];
	struct resource *axi_conf = dev->res[MSM_PCIE_RES_CONF].resource;
	u32 dev_conf, upper, lower, limit;

@@ -621,13 +580,7 @@ static void msm_pcie_config_controller(u32 rc_idx)
		limit = axi_conf->end;
	}

	if (rc_idx == 0) {
		/* Should equate to 0x01000000 */
	dev_conf = BDF_OFFSET(1, 0, 0);
	} else {
		/* Should equate to 0x03000000 */
		dev_conf = BDF_OFFSET(3, 0, 0);
	}

	/*
	 * program and enable address translation region 0 (device config
@@ -665,10 +618,8 @@ static void msm_pcie_config_controller(u32 rc_idx)
		readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
}

static void msm_pcie_config_l1ss(u32 rc_idx)
static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev)
{
	struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx];

	PCIE_DBG("Original PCIE20_ACK_F_ASPM_CTRL_REG:0x%x\n",
		readl_relaxed(dev->dm_core + PCIE20_ACK_F_ASPM_CTRL_REG));
	msm_pcie_write_mask(dev->dm_core + PCIE20_ACK_F_ASPM_CTRL_REG, 0,
@@ -704,7 +655,8 @@ static void msm_pcie_config_l1ss(u32 rc_idx)
					PCIE20_EP_L1SUB_CTL1_OFFSET));
}

static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
static int msm_pcie_get_resources(struct msm_pcie_dev_t *dev,
					struct platform_device *pdev)
{
	int i, len, cnt, ret = 0;
	struct msm_pcie_vreg_info_t *vreg_info;
@@ -713,7 +665,6 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
	struct resource *res;
	struct msm_pcie_res_info_t *res_info;
	struct msm_pcie_irq_info_t *irq_info;
	struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx];
	char prop_name[MAX_PROP_SIZE];
	const __be32 *prop;
	u32 *clkfreq = NULL;
@@ -747,8 +698,8 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
				devm_regulator_get(&pdev->dev, vreg_info->name);

		if (PTR_ERR(vreg_info->hdl) == -EPROBE_DEFER) {
			PCIE_DBG("EPROBE_DEFER for PCIe_%d:%s\n",
				rc_idx, vreg_info->name);
			PCIE_DBG("EPROBE_DEFER for VReg:%s\n",
				vreg_info->name);
			return PTR_ERR(vreg_info->hdl);
		}

@@ -784,11 +735,11 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
	dev->gdsc = devm_regulator_get(&pdev->dev, "gdsc-vdd");

	if (IS_ERR(dev->gdsc)) {
		pr_err("PCIe: Failed to get PCIe_%d GDSC:%ld\n",
			rc_idx, PTR_ERR(dev->gdsc));
		pr_err("PCIe: Failed to get %s GDSC:%ld\n",
			dev->pdev->name, PTR_ERR(dev->gdsc));
		if (PTR_ERR(dev->gdsc) == -EPROBE_DEFER)
			PCIE_DBG("PCIe: EPROBE_DEFER for PCIe_%d GDSC\n",
					rc_idx);
			PCIE_DBG("PCIe: EPROBE_DEFER for %s GDSC\n",
					dev->pdev->name);
		return PTR_ERR(dev->gdsc);
	}

@@ -809,7 +760,7 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
	}

	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
		clk_info = &msm_pcie_dev[rc_idx].clk[i];
		clk_info = &dev->clk[i];

		clk_info->hdl = devm_clk_get(&pdev->dev, clk_info->name);

@@ -833,7 +784,7 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
	}

	for (i = 0; i < MSM_PCIE_MAX_PIPE_CLK; i++) {
		clk_info = &msm_pcie_dev[rc_idx].pipeclk[i];
		clk_info = &dev->pipeclk[i];

		clk_info->hdl = devm_clk_get(&pdev->dev, clk_info->name);

@@ -917,21 +868,20 @@ static int msm_pcie_get_resources(u32 rc_idx, struct platform_device *pdev)
	return ret;
}

static void msm_pcie_release_resources(u32 rc_idx)
static void msm_pcie_release_resources(struct msm_pcie_dev_t *dev)
{
	msm_pcie_dev[rc_idx].parf = NULL;
	msm_pcie_dev[rc_idx].elbi = NULL;
	msm_pcie_dev[rc_idx].dm_core = NULL;
	msm_pcie_dev[rc_idx].conf = NULL;
	msm_pcie_dev[rc_idx].bars = NULL;
	msm_pcie_dev[rc_idx].dev_mem_res = NULL;
	msm_pcie_dev[rc_idx].dev_io_res = NULL;
	dev->parf = NULL;
	dev->elbi = NULL;
	dev->dm_core = NULL;
	dev->conf = NULL;
	dev->bars = NULL;
	dev->dev_mem_res = NULL;
	dev->dev_io_res = NULL;
}

static int msm_pcie_enable(u32 rc_idx, u32 options)
static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options)
{
	int ret;
	struct msm_pcie_dev_t *dev;
	uint32_t val;
	long int retries = 0;

@@ -939,8 +889,6 @@ static int msm_pcie_enable(u32 rc_idx, u32 options)

	mutex_lock(&setup_lock);

	dev = &msm_pcie_dev[rc_idx];

	/* assert PCIe reset link to keep EP in reset */

	gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
@@ -951,14 +899,14 @@ static int msm_pcie_enable(u32 rc_idx, u32 options)
	/* enable power */

	if (options & PM_VREG) {
		ret = msm_pcie_vreg_init(rc_idx, &dev->pdev->dev);
		ret = msm_pcie_vreg_init(dev);
		if (ret)
			goto out;
	}

	/* enable clocks */
	if (options & PM_CLK) {
		ret = msm_pcie_clk_init(rc_idx, &dev->pdev->dev);
		ret = msm_pcie_clk_init(dev);
		wmb();
		if (ret)
			goto clk_fail;
@@ -975,7 +923,7 @@ static int msm_pcie_enable(u32 rc_idx, u32 options)

	if (options & PM_PIPE_CLK) {
		/* Enable the pipe clock */
		ret = msm_pcie_pipe_clk_init(rc_idx, &dev->pdev->dev);
		ret = msm_pcie_pipe_clk_init(dev);
		wmb();
		if (ret)
			goto link_fail;
@@ -1042,27 +990,21 @@ static int msm_pcie_enable(u32 rc_idx, u32 options)
		goto link_fail;
	}

	msm_pcie_config_controller(rc_idx);
	msm_pcie_config_controller(dev);

	if (!dev->msi_gicm_addr)
		msm_pcie_config_msi_controller(dev);

	if (dev->l1ss_supported)
		msm_pcie_config_l1ss(rc_idx);
		msm_pcie_config_l1ss(dev);

	if (options & PM_IRQ) {
		ret = msm_pcie_irq_init(dev);
		if (!ret)
			goto out;
	} else {
	goto out;
	}

link_fail:
	msm_pcie_clk_deinit(rc_idx);
	msm_pcie_clk_deinit(dev);
clk_fail:
	msm_pcie_vreg_deinit(rc_idx);
	msm_pcie_pipe_clk_deinit(rc_idx);
	msm_pcie_vreg_deinit(dev);
	msm_pcie_pipe_clk_deinit(dev);
out:
	dev->link_status = MSM_PCIE_LINK_ENABLED;
	mutex_unlock(&setup_lock);
@@ -1071,53 +1013,43 @@ out:
}


void msm_pcie_disable(u32 rc_idx, u32 options)
void msm_pcie_disable(struct msm_pcie_dev_t *dev, u32 options)
{
	struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx];

	PCIE_DBG("\n");

	gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
				dev->gpio[MSM_PCIE_GPIO_PERST].on);

	if (options & PM_IRQ)
		msm_pcie_irq_deinit(dev);

	if (options & PM_CLK) {
		msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, 0,
					BIT(0));
		msm_pcie_clk_deinit(rc_idx);
		msm_pcie_clk_deinit(dev);
	}

	if (options & PM_VREG)
		msm_pcie_vreg_deinit(rc_idx);
		msm_pcie_vreg_deinit(dev);

	if (options & PM_PIPE_CLK)
		msm_pcie_pipe_clk_deinit(rc_idx);
		msm_pcie_pipe_clk_deinit(dev);

	dev->link_status = MSM_PCIE_LINK_DISABLED;
}

static int msm_pcie_setup(int nr, struct pci_sys_data *sys)
{
	static bool init;

	PCIE_DBG("bus %d\n", nr);

	/*
	 * specify linux PCI framework to allocate device memory (BARs)
	 * from msm_pcie_dev.dev_mem_res resource.
	 */
	if (!init) {
	sys->mem_offset = 0;
	sys->io_offset = 0;
		init = true;
	}

	pci_add_resource(&sys->resources,
			msm_pcie_dev[pcie_drv.current_rc].dev_io_res);
		((struct msm_pcie_dev_t *)(sys->private_data))->dev_io_res);
	pci_add_resource(&sys->resources,
			msm_pcie_dev[pcie_drv.current_rc].dev_mem_res);
		((struct msm_pcie_dev_t *)(sys->private_data))->dev_mem_res);
	return 1;
}

@@ -1136,23 +1068,23 @@ static struct pci_bus *msm_pcie_scan_bus(int nr,

static int msm_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
	u32 rc_idx = pcie_drv.current_rc;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);
	int ret = 0;

	PCIE_DBG("rc %d slot %d pin %d\n", rc_idx, slot, pin);
	PCIE_DBG("rc %s slot %d pin %d\n", pcie_dev->pdev->name, slot, pin);

	switch (pin) {
	case 1:
		ret = msm_pcie_dev[rc_idx].irq[MSM_PCIE_INT_A].num;
		ret = pcie_dev->irq[MSM_PCIE_INT_A].num;
		break;
	case 2:
		ret = msm_pcie_dev[rc_idx].irq[MSM_PCIE_INT_B].num;
		ret = pcie_dev->irq[MSM_PCIE_INT_B].num;
		break;
	case 3:
		ret = msm_pcie_dev[rc_idx].irq[MSM_PCIE_INT_C].num;
		ret = pcie_dev->irq[MSM_PCIE_INT_C].num;
		break;
	case 4:
		ret = msm_pcie_dev[rc_idx].irq[MSM_PCIE_INT_D].num;
		ret = pcie_dev->irq[MSM_PCIE_INT_D].num;
		break;
	default:
		pr_err("PCIe: unsupported pin number.\n");
@@ -1161,19 +1093,58 @@ static int msm_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
	return ret;
}

static struct hw_pci msm_pci = {
	.nr_controllers	= MAX_RC_NUM,

static struct hw_pci msm_pci[MAX_RC_NUM] = {
	{
	.domain = 0,
	.nr_controllers	= 1,
	.swizzle	= pci_common_swizzle,
	.setup		= msm_pcie_setup,
	.scan		= msm_pcie_scan_bus,
	.map_irq	= msm_pcie_map_irq,
	},
	{
	.domain = 1,
	.nr_controllers	= 1,
	.swizzle	= pci_common_swizzle,
	.setup		= msm_pcie_setup,
	.scan		= msm_pcie_scan_bus,
	.map_irq	= msm_pcie_map_irq,
	},
};

int msm_pcie_enumerate(u32 rc_idx)
{
	int ret = 0;
	struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx];

	PCIE_DBG("Enumerate RC %d\n", rc_idx);

	if (!dev->enumerated) {
		ret = msm_pcie_enable(dev, PM_ALL);

		/* kick start ARM PCI configuration framework */
		if (!ret) {
			msm_pci[rc_idx].private_data = (void **)&dev;
			pci_common_init(&msm_pci[rc_idx]);
			/* This has to happen only once */
			dev->enumerated = true;
		} else {
			pr_err("PCIe: %s: failed to enable RC %d.\n",
				__func__, dev->rc_idx);
		}
	} else {
		pr_err("PCIe: %s: RC %d has already been enumerated.\n",
			__func__, dev->rc_idx);
	}

	return ret;
}

static int msm_pcie_probe(struct platform_device *pdev)
{
	int ret = 0;
	int rc_idx;
	struct msm_pcie_dev_t *dev;

	PCIE_DBG("\n");

@@ -1246,6 +1217,7 @@ static int msm_pcie_probe(struct platform_device *pdev)
		}
	}

	msm_pcie_dev[rc_idx].rc_idx = rc_idx;
	msm_pcie_dev[rc_idx].pdev = pdev;
	msm_pcie_dev[rc_idx].vreg_n = 0;
	msm_pcie_dev[rc_idx].gpio_n = 0;
@@ -1254,6 +1226,7 @@ static int msm_pcie_probe(struct platform_device *pdev)
	msm_pcie_dev[rc_idx].link_status = MSM_PCIE_LINK_DEINIT;
	msm_pcie_dev[rc_idx].user_suspend = false;
	msm_pcie_dev[rc_idx].saved_state = NULL;
	msm_pcie_dev[rc_idx].enumerated = false;
	memcpy(msm_pcie_dev[rc_idx].vreg, msm_pcie_vreg_info,
				sizeof(msm_pcie_vreg_info));
	memcpy(msm_pcie_dev[rc_idx].gpio, msm_pcie_gpio_info,
@@ -1267,36 +1240,33 @@ static int msm_pcie_probe(struct platform_device *pdev)
	memcpy(msm_pcie_dev[rc_idx].irq, msm_pcie_irq_info,
				sizeof(msm_pcie_irq_info));

	ret = msm_pcie_get_resources(rc_idx, msm_pcie_dev[rc_idx].pdev);
	ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx],
				msm_pcie_dev[rc_idx].pdev);

	if (ret)
		goto decrease_rc_num;

	ret = msm_pcie_gpio_init(rc_idx);
	ret = msm_pcie_gpio_init(&msm_pcie_dev[rc_idx]);
	if (ret) {
		msm_pcie_release_resources(rc_idx);
		msm_pcie_release_resources(&msm_pcie_dev[rc_idx]);
		goto decrease_rc_num;
	}

	ret = msm_pcie_enable(rc_idx, PM_ALL);
	ret = msm_pcie_irq_init(&msm_pcie_dev[rc_idx]);
	if (ret) {
		pr_err("PCIe:failed to enable PCIe link in bootup\n");
		msm_pcie_gpio_deinit(rc_idx);
		msm_pcie_release_resources(rc_idx);
		msm_pcie_release_resources(&msm_pcie_dev[rc_idx]);
		msm_pcie_gpio_deinit(&msm_pcie_dev[rc_idx]);
		goto decrease_rc_num;
	}

	/* kick start ARM PCI configuration framework */
	if (pcie_drv.rc_num == pcie_drv.rc_expected) {
		msm_pci.nr_controllers = pcie_drv.rc_num;
		if (pcie_drv.rc_expected > 1)
			pcie_drv.current_rc = 0;
	ret = msm_pcie_enumerate(rc_idx);

	if (ret)
		pr_err(
			"PCIe:failed to enable RC %d in bootup; it will be enumerated upon WAKE signal.\n",
			rc_idx);
	else
			pcie_drv.current_rc = rc_idx;
		dev = &msm_pcie_dev[rc_idx];
		msm_pci.private_data = (void **)&dev;
		pci_common_init(&msm_pci);
	}
		PCIE_DBG("RC %d is enabled in bootup\n", rc_idx);

	msm_pcie_dev[rc_idx].dev = pci_get_device(PCIE_VENDOR_ID_RCP,
					PCIE_DEVICE_ID_RCP, NULL);
@@ -1332,10 +1302,10 @@ static int __exit msm_pcie_remove(struct platform_device *pdev)
	}

	msm_pcie_irq_deinit(&msm_pcie_dev[rc_idx]);
	msm_pcie_vreg_deinit(rc_idx);
	msm_pcie_clk_deinit(rc_idx);
	msm_pcie_gpio_deinit(rc_idx);
	msm_pcie_release_resources(rc_idx);
	msm_pcie_vreg_deinit(&msm_pcie_dev[rc_idx]);
	msm_pcie_clk_deinit(&msm_pcie_dev[rc_idx]);
	msm_pcie_gpio_deinit(&msm_pcie_dev[rc_idx]);
	msm_pcie_release_resources(&msm_pcie_dev[rc_idx]);

out:
	mutex_unlock(&pcie_drv.drv_lock);
@@ -1402,17 +1372,19 @@ DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
			msm_pcie_fixup_early);

/* Suspend the PCIe link */
static int msm_pcie_pm_suspend(struct pci_dev *dev, u32 rc_idx,
static int msm_pcie_pm_suspend(struct pci_dev *dev,
			void *user, void *data, u32 options)
{
	int ret = 0;
	u32 val = 0;
	int ret_l23;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);

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

	if (dev) {
		ret = pci_save_state(dev);
		msm_pcie_dev[rc_idx].saved_state =
					pci_store_saved_state(dev);
		pcie_dev->saved_state =	pci_store_saved_state(dev);
	}
	if (ret) {
		pr_err("PCIe: fail to save state of RC 0x%p:%d.\n",
@@ -1429,18 +1401,18 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, u32 rc_idx,
		}
	}

	spin_lock_irqsave(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	msm_pcie_dev[rc_idx].cfg_access = false;
	spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	spin_lock_irqsave(&pcie_dev->cfg_lock,
				pcie_dev->irqsave_flags);
	pcie_dev->cfg_access = false;
	spin_unlock_irqrestore(&pcie_dev->cfg_lock,
				pcie_dev->irqsave_flags);

	msm_pcie_write_mask(msm_pcie_dev[rc_idx].elbi + PCIE20_ELBI_SYS_CTRL, 0,
	msm_pcie_write_mask(pcie_dev->elbi + PCIE20_ELBI_SYS_CTRL, 0,
				BIT(4));

	PCIE_DBG("PME_TURNOFF_MSG is sent out\n");

	ret_l23 = readl_poll_timeout((msm_pcie_dev[rc_idx].parf
	ret_l23 = readl_poll_timeout((pcie_dev->parf
		+ PCIE20_PARF_PM_STTS), val, (val & BIT(6)), 10000, 100000);

	/* check L23_Ready */
@@ -1449,7 +1421,7 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, u32 rc_idx,
	else
		PCIE_DBG("PM_Enter_L23 is NOT received\n");

	msm_pcie_disable(rc_idx, PM_PIPE_CLK | PM_CLK | PM_VREG);
	msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);

	return ret;
}
@@ -1457,12 +1429,14 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, u32 rc_idx,
static void msm_pcie_fixup_suspend(struct pci_dev *dev)
{
	int ret;
	u32 rc_idx = pcie_drv.current_rc;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);

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

	if (msm_pcie_dev[rc_idx].link_status != MSM_PCIE_LINK_ENABLED)
	if (pcie_dev->link_status != MSM_PCIE_LINK_ENABLED)
		return;

	ret = msm_pcie_pm_suspend(dev, rc_idx, NULL, NULL, 0);
	ret = msm_pcie_pm_suspend(dev, NULL, NULL, 0);
	if (ret)
		pr_err("PCIe: got failure in suspend:%d.\n", ret);
}
@@ -1470,18 +1444,21 @@ DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
			  msm_pcie_fixup_suspend);

/* Resume the PCIe link */
static int msm_pcie_pm_resume(struct pci_dev *dev, u32 rc_idx,
static int msm_pcie_pm_resume(struct pci_dev *dev,
			void *user, void *data, u32 options)
{
	int ret;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);

	spin_lock_irqsave(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	msm_pcie_dev[rc_idx].cfg_access = true;
	spin_unlock_irqrestore(&msm_pcie_dev[rc_idx].cfg_lock,
				msm_pcie_dev[rc_idx].irqsave_flags);
	PCIE_DBG("RC %d\n", pcie_dev->rc_idx);

	ret = msm_pcie_enable(rc_idx, PM_PIPE_CLK | PM_CLK | PM_VREG);
	spin_lock_irqsave(&pcie_dev->cfg_lock,
				pcie_dev->irqsave_flags);
	pcie_dev->cfg_access = true;
	spin_unlock_irqrestore(&pcie_dev->cfg_lock,
				pcie_dev->irqsave_flags);

	ret = msm_pcie_enable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
	if (ret) {
		pr_err("PCIe:fail to enable PCIe link in resume\n");
		return ret;
@@ -1489,8 +1466,7 @@ static int msm_pcie_pm_resume(struct pci_dev *dev, u32 rc_idx,
		PCIE_DBG("dev->bus->number = %d dev->bus->primary = %d\n",
			 dev->bus->number, dev->bus->primary);

		pci_load_and_free_saved_state(dev,
					&msm_pcie_dev[rc_idx].saved_state);
		pci_load_and_free_saved_state(dev, &pcie_dev->saved_state);

		pci_restore_state(dev);

@@ -1504,15 +1480,15 @@ static int msm_pcie_pm_resume(struct pci_dev *dev, u32 rc_idx,
void msm_pcie_fixup_resume(struct pci_dev *dev)
{
	int ret;
	u32 rc_idx = pcie_drv.current_rc;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);

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

	if ((msm_pcie_dev[rc_idx].link_status != MSM_PCIE_LINK_DISABLED) ||
		msm_pcie_dev[rc_idx].user_suspend)
	if ((pcie_dev->link_status != MSM_PCIE_LINK_DISABLED) ||
		pcie_dev->user_suspend)
		return;

	ret = msm_pcie_pm_resume(dev, rc_idx, NULL, NULL, 0);
	ret = msm_pcie_pm_resume(dev, NULL, NULL, 0);
	if (ret)
		pr_err("PCIe: got failure in fixup resume:%d.\n", ret);
}
@@ -1522,13 +1498,15 @@ DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
void msm_pcie_fixup_resume_early(struct pci_dev *dev)
{
	int ret;
	u32 rc_idx = pcie_drv.current_rc;
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);

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

	if ((msm_pcie_dev[rc_idx].link_status != MSM_PCIE_LINK_DISABLED) ||
		msm_pcie_dev[rc_idx].user_suspend)
	if ((pcie_dev->link_status != MSM_PCIE_LINK_DISABLED) ||
		pcie_dev->user_suspend)
		return;

	ret = msm_pcie_pm_resume(dev, rc_idx, NULL, NULL, 0);
	ret = msm_pcie_pm_resume(dev, NULL, NULL, 0);
	if (ret)
		pr_err("PCIe: got failure in resume:%d.\n", ret);
}
@@ -1537,9 +1515,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,

static void msm_pcie_fixup_final(struct pci_dev *dev)
{
	PCIE_DBG("\n");

	if (pcie_drv.rc_expected > 1)
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev);
	PCIE_DBG("RC %d\n", pcie_dev->rc_idx);
	pcie_drv.current_rc++;
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);
@@ -1553,16 +1530,8 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user,

	switch (busnr) {
	case 1:
		if (pcie_drv.rc_expected > 1)
		if (!options)
			rc_idx = 0;
		else
			rc_idx = pcie_drv.current_rc;
		break;
	case 3:
		if (pcie_drv.rc_expected > 1)
			rc_idx = 1;
		else
			rc_idx = pcie_drv.current_rc;
		break;
	default:
		pr_err("PCIe: unsupported bus number.\n");
@@ -1581,7 +1550,7 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user,
			break;
		}
		msm_pcie_dev[rc_idx].user_suspend = true;
		ret = msm_pcie_pm_suspend(dev, rc_idx, user, data, options);
		ret = msm_pcie_pm_suspend(dev, user, data, options);
		if (ret) {
			pr_err("PCIe: user failed to suspend the link.\n");
			msm_pcie_dev[rc_idx].user_suspend = false;
@@ -1595,7 +1564,7 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user,
				msm_pcie_dev[rc_idx].link_status);
			break;
		}
		ret = msm_pcie_pm_resume(dev, rc_idx, user, data, options);
		ret = msm_pcie_pm_resume(dev, user, data, options);
		if (ret)
			pr_err("PCIe: user failed to resume the link.\n");
		else
+5 −0
Original line number Diff line number Diff line
@@ -174,8 +174,13 @@ struct msm_pcie_dev_t {

	bool                         l1ss_supported;
	bool                         aux_clk_sync;

	uint32_t                     rc_idx;
	bool                         enumerated;
	struct work_struct	     handle_wake_work;
};

extern int msm_pcie_enumerate(u32 rc_idx);
extern void msm_pcie_config_msi_controller(struct msm_pcie_dev_t *dev);
extern int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
extern void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev);
+32 −3

File changed.

Preview size limit exceeded, changes collapsed.