Exemple #1
0
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
{
	u8 hdr_type;
	u32 link_ctrl;
	u16 pos, link_status;
	int link_is_active = 0;

	/* make sure we are not in EP mode */
	pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
	if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) {
		dev_err(pcie->dev, "in EP mode, hdr=%#02x\n", hdr_type);
		return -EFAULT;
	}

	/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
	pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE,
				  PCI_CLASS_BRIDGE_PCI);

	/* check link status to see if link is active */
	pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
	pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
	if (link_status & PCI_EXP_LNKSTA_NLW)
		link_is_active = 1;

	if (!link_is_active) {
		/* try GEN 1 link speed */
#define PCI_LINK_STATUS_CTRL_2_OFFSET 0x0dc
#define PCI_TARGET_LINK_SPEED_MASK    0xf
#define PCI_TARGET_LINK_SPEED_GEN2    0x2
#define PCI_TARGET_LINK_SPEED_GEN1    0x1
		pci_bus_read_config_dword(bus, 0,
					  PCI_LINK_STATUS_CTRL_2_OFFSET,
					  &link_ctrl);
		if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) ==
		    PCI_TARGET_LINK_SPEED_GEN2) {
			link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK;
			link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1;
			pci_bus_write_config_dword(bus, 0,
					   PCI_LINK_STATUS_CTRL_2_OFFSET,
					   link_ctrl);
			msleep(100);

			pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
			pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
						 &link_status);
			if (link_status & PCI_EXP_LNKSTA_NLW)
				link_is_active = 1;
		}
	}

	dev_info(pcie->dev, "link: %s\n", link_is_active ? "UP" : "DOWN");

	return link_is_active ? 0 : -ENODEV;
}
Exemple #2
0
int cpci_set_attention_status(struct slot* slot, int status)
{
    int hs_cap;
    u16 hs_csr;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return 0;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return 0;
    if (status)
        hs_csr |= HS_CSR_LOO;
    else
        hs_csr &= ~HS_CSR_LOO;
    if (pci_bus_write_config_word(slot->bus,
                      slot->devfn,
                      hs_cap + 2,
                      hs_csr))
        return 0;
    return 1;
}
Exemple #3
0
int cpci_led_off(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return -ENODEV;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return -ENODEV;
    if (hs_csr & HS_CSR_LOO) {
        hs_csr &= ~HS_CSR_LOO;
        if (pci_bus_write_config_word(slot->bus,
                          slot->devfn,
                          hs_cap + 2,
                          hs_csr)) {
            err("Could not clear LOO for slot %s",
                slot->hotplug_slot->name);
            return -ENODEV;
        }
    }
    return 0;
}
Exemple #4
0
int cpci_clear_ext(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return -ENODEV;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return -ENODEV;
    if (hs_csr & HS_CSR_EXT) {
        /* Clear EXT (by setting it) */
        if (pci_bus_write_config_word(slot->bus,
                          slot->devfn,
                          hs_cap + 2,
                          hs_csr))
            return -ENODEV;
    }
    return 0;
}
Exemple #5
0
int cpci_check_and_clear_ins(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;
    int ins = 0;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return 0;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return 0;
    if (hs_csr & HS_CSR_INS) {
        /* Clear INS (by setting it) */
        if (pci_bus_write_config_word(slot->bus,
                          slot->devfn,
                          hs_cap + 2,
                          hs_csr))
            ins = 0;
        else
            ins = 1;
    }
    return ins;
}
Exemple #6
0
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
{
	if (pci_dev_is_disconnected(dev)) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}
	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
}
Exemple #7
0
u16 cpci_get_hs_csr(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return 0xFFFF;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return 0xFFFF;
    return hs_csr;
}
Exemple #8
0
u8 cpci_get_attention_status(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return 0;

    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return 0;

    return hs_csr & 0x0008 ? 1 : 0;
}
Exemple #9
0
int cpci_check_ext(struct slot* slot)
{
    int hs_cap;
    u16 hs_csr;
    int ext = 0;

    hs_cap = pci_bus_find_capability(slot->bus,
                     slot->devfn,
                     PCI_CAP_ID_CHSWP);
    if (!hs_cap)
        return 0;
    if (pci_bus_read_config_word(slot->bus,
                     slot->devfn,
                     hs_cap + 2,
                     &hs_csr))
        return 0;
    if (hs_csr & HS_CSR_EXT)
        ext = 1;
    return ext;
}
Exemple #10
0
static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
{
	u8 config, rev;
	u16 word;

	/* BIOS may enable hardware IRQ balancing for
	 * E7520/E7320/E7525(revision ID 0x9 and below)
	 * based platforms.
	 * Disable SW irqbalance/affinity on those platforms.
	 */
	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
	if (rev > 0x9)
		return;

	/* enable access to config space*/
	pci_read_config_byte(dev, 0xf4, &config);
	pci_write_config_byte(dev, 0xf4, config|0x2);

	/*
	 * read xTPR register.  We may not have a pci_dev for device 8
	 * because it might be hidden until the above write.
	 */
	pci_bus_read_config_word(dev->bus, PCI_DEVFN(8, 0), 0x4c, &word);

	if (!(word & (1 << 13))) {
		dev_info(&dev->dev, "Intel E7520/7320/7525 detected; "
			"disabling irq balancing and affinity\n");
		noirqdebug_setup("");
#ifdef CONFIG_PROC_FS
		no_irq_affinity = 1;
#endif
	}

	/* put back the original value for config space*/
	if (!(config & 0x2))
		pci_write_config_byte(dev, 0xf4, config);
}
static unsigned long i915_stolen_to_physical(struct drm_i915_private *dev_priv)
{
	struct pci_dev *pdev = dev_priv->drm.pdev;
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	struct resource *r;
	u32 base;

	/* Almost universally we can find the Graphics Base of Stolen Memory
	 * at register BSM (0x5c) in the igfx configuration space. On a few
	 * (desktop) machines this is also mirrored in the bridge device at
	 * different locations, or in the MCHBAR.
	 *
	 * On 865 we just check the TOUD register.
	 *
	 * On 830/845/85x the stolen memory base isn't available in any
	 * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size.
	 *
	 */
	base = 0;
	if (INTEL_GEN(dev_priv) >= 3) {
		u32 bsm;

		pci_read_config_dword(pdev, INTEL_BSM, &bsm);

		base = bsm & INTEL_BSM_MASK;
	} else if (IS_I865G(dev_priv)) {
		u32 tseg_size = 0;
		u16 toud = 0;
		u8 tmp;

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I845_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE) {
			switch (tmp & I845_TSEG_SIZE_MASK) {
			case I845_TSEG_SIZE_512K:
				tseg_size = KB(512);
				break;
			case I845_TSEG_SIZE_1M:
				tseg_size = MB(1);
				break;
			}
		}

		pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0),
					 I865_TOUD, &toud);

		base = (toud << 16) + tseg_size;
	} else if (IS_I85X(dev_priv)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I85X_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE)
			tseg_size = MB(1);

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 1),
					 I85X_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - ggtt->stolen_size;
	} else if (IS_845G(dev_priv)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I845_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE) {
			switch (tmp & I845_TSEG_SIZE_MASK) {
			case I845_TSEG_SIZE_512K:
				tseg_size = KB(512);
				break;
			case I845_TSEG_SIZE_1M:
				tseg_size = MB(1);
				break;
			}
		}

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I830_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - ggtt->stolen_size;
	} else if (IS_I830(dev_priv)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I830_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE) {
			if (tmp & I830_TSEG_SIZE_1M)
				tseg_size = MB(1);
			else
				tseg_size = KB(512);
		}

		pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
					 I830_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - ggtt->stolen_size;
	}

	if (base == 0)
		return 0;

	/* make sure we don't clobber the GTT if it's within stolen memory */
	if (INTEL_GEN(dev_priv) <= 4 && !IS_G33(dev_priv) &&
	    !IS_G4X(dev_priv)) {
		struct {
			u32 start, end;
		} stolen[2] = {
			{ .start = base, .end = base + ggtt->stolen_size, },
			{ .start = base, .end = base + ggtt->stolen_size, },
		};
Exemple #12
0
Fichier : pcie.c Projet : 01org/prd
static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
{
	int port = cnspci->port;
	struct pci_sys_data sd = {
		.private_data = cnspci,
	};
	struct pci_bus bus = {
		.number = 0,
		.ops = &cns3xxx_pcie_ops,
		.sysdata = &sd,
	};
	u16 mem_base  = cnspci->res_mem.start >> 16;
	u16 mem_limit = cnspci->res_mem.end   >> 16;
	u16 io_base   = cnspci->res_io.start  >> 16;
	u16 io_limit  = cnspci->res_io.end    >> 16;
	u32 devfn = 0;
	u8 tmp8;
	u16 pos;
	u16 dc;

	pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
	pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
	pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);

	pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8);
	pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8);
	pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);

	pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
	pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit);
	pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
	pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit);

	if (!cnspci->linked)
		return;

	/* Set Device Max_Read_Request_Size to 128 byte */
	bus.number = 1; /* directly connected PCIe device */
	devfn = PCI_DEVFN(0, 0);
	pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
	pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
	if (dc & PCI_EXP_DEVCTL_READRQ) {
		dc &= ~PCI_EXP_DEVCTL_READRQ;
		pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc);
		pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
		if (dc & PCI_EXP_DEVCTL_READRQ)
			pr_warn("PCIe: Unable to set device Max_Read_Request_Size\n");
		else
			pr_info("PCIe: Max_Read_Request_Size set to 128 bytes\n");
	}
	/* Disable PCIe0 Interrupt Mask INTA to INTD */
	__raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port));
}

static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
				      struct pt_regs *regs)
{
	if (fsr & (1 << 10))
		regs->ARM_pc += 4;
	return 0;
}

void __init cns3xxx_pcie_init_late(void)
{
	int i;
	void *private_data;
	struct hw_pci hw_pci = {
	       .nr_controllers = 1,
	       .ops = &cns3xxx_pcie_ops,
	       .setup = cns3xxx_pci_setup,
	       .map_irq = cns3xxx_pcie_map_irq,
	       .private_data = &private_data,
	};

	pcibios_min_io = 0;
	pcibios_min_mem = 0;

	hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
			"imprecise external abort");

	for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
		cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
		cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
		cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
		cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
		private_data = &cns3xxx_pcie[i];
		pci_common_init(&hw_pci);
	}

	pci_assign_unassigned_resources();
}
Exemple #13
0
static unsigned long i915_stolen_to_physical(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 base;

	/* Almost universally we can find the Graphics Base of Stolen Memory
	 * at offset 0x5c in the igfx configuration space. On a few (desktop)
	 * machines this is also mirrored in the bridge device at different
	 * locations, or in the MCHBAR.
	 *
	 * On 865 we just check the TOUD register.
	 *
	 * On 830/845/85x the stolen memory base isn't available in any
	 * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size.
	 *
	 */
	base = 0;
	if (INTEL_INFO(dev)->gen >= 3) {
		/* Read Graphics Base of Stolen Memory directly */
		pci_read_config_dword(dev->pdev, 0x5c, &base);
		base &= ~((1<<20) - 1);
#if 0
	} else if (IS_I865G(dev)) {
		u16 toud = 0;

		/*
		 * FIXME is the graphics stolen memory region
		 * always at TOUD? Ie. is it always the last
		 * one to be allocated by the BIOS?
		 */
		pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I865_TOUD, &toud);

		base = toud << 16;
	} else if (IS_I85X(dev)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I85X_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE)
			tseg_size = MB(1);

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1),
					 I85X_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - dev_priv->gtt.stolen_size;
	} else if (IS_845G(dev)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I845_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE) {
			switch (tmp & I845_TSEG_SIZE_MASK) {
			case I845_TSEG_SIZE_512K:
				tseg_size = KB(512);
				break;
			case I845_TSEG_SIZE_1M:
				tseg_size = MB(1);
				break;
			}
		}

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I830_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - dev_priv->gtt.stolen_size;
	} else if (IS_I830(dev)) {
		u32 tseg_size = 0;
		u32 tom;
		u8 tmp;

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I830_ESMRAMC, &tmp);

		if (tmp & TSEG_ENABLE) {
			if (tmp & I830_TSEG_SIZE_1M)
				tseg_size = MB(1);
			else
				tseg_size = KB(512);
		}

		pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
					 I830_DRB3, &tmp);
		tom = tmp * MB(32);

		base = tom - tseg_size - dev_priv->gtt.stolen_size;
#endif
	}

	if (base == 0)
		return 0;

	/* make sure we don't clobber the GTT if it's within stolen memory */
	if (INTEL_INFO(dev)->gen <= 4 && !IS_G33(dev) && !IS_G4X(dev)) {
		struct {
			u32 start, end;
		} stolen[2] = {
			{ .start = base, .end = base + dev_priv->gtt.stolen_size, },
			{ .start = base, .end = base + dev_priv->gtt.stolen_size, },
		};
Exemple #14
0
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
{
	struct device *dev = pcie->dev;
	u8 hdr_type;
	u32 link_ctrl, class, val;
	u16 pos = PCI_EXP_CAP, link_status;
	bool link_is_active = false;

	/*
	 * PAXC connects to emulated endpoint devices directly and does not
	 * have a Serdes.  Therefore skip the link detection logic here.
	 */
	if (pcie->type == IPROC_PCIE_PAXC)
		return 0;

	val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS);
	if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
		dev_err(dev, "PHY or data link is INACTIVE!\n");
		return -ENODEV;
	}

	/* make sure we are not in EP mode */
	pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
	if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) {
		dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type);
		return -EFAULT;
	}

	/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
#define PCI_CLASS_BRIDGE_MASK      0xffff00
#define PCI_CLASS_BRIDGE_SHIFT     8
	pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class);
	class &= ~PCI_CLASS_BRIDGE_MASK;
	class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
	pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class);

	/* check link status to see if link is active */
	pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
	if (link_status & PCI_EXP_LNKSTA_NLW)
		link_is_active = true;

	if (!link_is_active) {
		/* try GEN 1 link speed */
#define PCI_TARGET_LINK_SPEED_MASK    0xf
#define PCI_TARGET_LINK_SPEED_GEN2    0x2
#define PCI_TARGET_LINK_SPEED_GEN1    0x1
		pci_bus_read_config_dword(bus, 0,
					  pos + PCI_EXP_LNKCTL2,
					  &link_ctrl);
		if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) ==
		    PCI_TARGET_LINK_SPEED_GEN2) {
			link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK;
			link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1;
			pci_bus_write_config_dword(bus, 0,
					   pos + PCI_EXP_LNKCTL2,
					   link_ctrl);
			msleep(100);

			pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
						 &link_status);
			if (link_status & PCI_EXP_LNKSTA_NLW)
				link_is_active = true;
		}
	}

	dev_info(dev, "link: %s\n", link_is_active ? "UP" : "DOWN");

	return link_is_active ? 0 : -ENODEV;
}
Exemple #15
0
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
{
	u8 hdr_type;
	u32 link_ctrl, class, val;
	u16 pos, link_status;
	bool link_is_active = false;

	val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET);
	if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
		dev_err(pcie->dev, "PHY or data link is INACTIVE!\n");
		return -ENODEV;
	}

	/* make sure we are not in EP mode */
	pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
	if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) {
		dev_err(pcie->dev, "in EP mode, hdr=%#02x\n", hdr_type);
		return -EFAULT;
	}

	/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
#define PCI_CLASS_BRIDGE_MASK      0xffff00
#define PCI_CLASS_BRIDGE_SHIFT     8
	pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class);
	class &= ~PCI_CLASS_BRIDGE_MASK;
	class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
	pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class);

	/* check link status to see if link is active */
	pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
	pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
	if (link_status & PCI_EXP_LNKSTA_NLW)
		link_is_active = true;

	if (!link_is_active) {
		/* try GEN 1 link speed */
#define PCI_LINK_STATUS_CTRL_2_OFFSET 0x0dc
#define PCI_TARGET_LINK_SPEED_MASK    0xf
#define PCI_TARGET_LINK_SPEED_GEN2    0x2
#define PCI_TARGET_LINK_SPEED_GEN1    0x1
		pci_bus_read_config_dword(bus, 0,
					  PCI_LINK_STATUS_CTRL_2_OFFSET,
					  &link_ctrl);
		if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) ==
		    PCI_TARGET_LINK_SPEED_GEN2) {
			link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK;
			link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1;
			pci_bus_write_config_dword(bus, 0,
					   PCI_LINK_STATUS_CTRL_2_OFFSET,
					   link_ctrl);
			msleep(100);

			pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
			pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
						 &link_status);
			if (link_status & PCI_EXP_LNKSTA_NLW)
				link_is_active = true;
		}
	}

	dev_info(pcie->dev, "link: %s\n", link_is_active ? "UP" : "DOWN");

	return link_is_active ? 0 : -ENODEV;
}