Re: Problem in reading cfg space of device connected below a bridge

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



You can see the patch for arch specific code at:

http://permalink.gmane.org/gmane.linux.ports.arm.kernel/88754

Yes , there are different methods to generate cfg0 and cfg1 in my controller.
I had already tried that , but it is not helping.
This modification is not in posted patch. So I am pesting the pcie_ops
basic cfg rd/wr routine here:

----------------------------------------------------------------------------------------------------------------------
static int spear13xx_pcie_rd_conf(struct pcie_port *pp, struct pci_bus *bus,
		u32 devfn, int where, int size, u32 *val)
{
	struct pcie_app_reg *app_reg = (struct pcie_app_reg *) pp->va_app_base;
	u32 address = (u32)pp->va_cfg0_base | (PCI_FUNC(devfn) << 16)
		| (where & 0xFFFC);

	writel((bus->number << 24) | (PCI_SLOT(devfn) << 19),
			&app_reg->pom_cfg0_addr_start);
	writel(readl(&app_reg->slv_armisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_armisc);
	if (bus->parent->number == pp->root_bus_nr)
		writel(readl(&app_reg->slv_armisc) |
				AXI_OP_TYPE_CONFIG_RDRW_TYPE0,
				&app_reg->slv_armisc);
	else
		writel(readl(&app_reg->slv_armisc) |
				AXI_OP_TYPE_CONFIG_RDRW_TYPE1,
				&app_reg->slv_armisc);
	udelay(1);
	*val = readl(address);
	if (size == 1)
		*val = (*val >> (8 * (where & 3))) & 0xff;
	else if (size == 2)
		*val = (*val >> (8 * (where & 3))) & 0xffff;

	writel(readl(&app_reg->slv_armisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_armisc);

	return PCIBIOS_SUCCESSFUL;
}

static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
			int size, u32 *val)
{
	struct pcie_port *pp = bus_to_port(bus->number);
	unsigned long flags;
	int ret;

	if (pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
		*val = 0xffffffff;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}

	spin_lock_irqsave(&pp->conf_lock, flags);
	if (bus->number != pp->root_bus_nr)
		ret = spear13xx_pcie_rd_conf(pp, bus, devfn, where, size, val);
	else {
		spear_dbi_read_reg(pp, where, size, val);
		ret = 0;
	}
	spin_unlock_irqrestore(&pp->conf_lock, flags);

	return ret;
}

static int spear13xx_pcie_wr_conf(struct pcie_port *pp, struct pci_bus *bus,
		u32 devfn, int where, int size, u32 val)
{
	int ret = PCIBIOS_SUCCESSFUL;
	struct pcie_app_reg *app_reg = (struct pcie_app_reg *) pp->va_app_base;
	u32 address = (u32)pp->va_cfg0_base | (PCI_FUNC(devfn) << 16)
			| (where & 0xFFFC);

	writel((bus->number << 24) | (PCI_SLOT(devfn) << 19),
			&app_reg->pom_cfg0_addr_start);
	writel(readl(&app_reg->slv_awmisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_awmisc);
	if (bus->parent->number == pp->root_bus_nr)
		writel(readl(&app_reg->slv_awmisc)
				| AXI_OP_TYPE_CONFIG_RDRW_TYPE0,
				&app_reg->slv_awmisc);
	else
		writel(readl(&app_reg->slv_awmisc)
				| AXI_OP_TYPE_CONFIG_RDRW_TYPE1,
				&app_reg->slv_awmisc);
	if (size == 4)
		writel(val, address);
	else if (size == 2)
		writew(val, address + (where & 2));
	else if (size == 1)
		writeb(val, address + (where & 3));
	else
		ret = PCIBIOS_BAD_REGISTER_NUMBER;
	writel(readl(&app_reg->slv_awmisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_awmisc);
	return ret;
}

static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
			int where, int size, u32 val)
{
	struct pcie_port *pp = bus_to_port(bus->number);
	unsigned long flags;
	int ret;

	if (pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
		return PCIBIOS_DEVICE_NOT_FOUND;

	spin_lock_irqsave(&pp->conf_lock, flags);
	if (bus->number != pp->root_bus_nr)
		ret = spear13xx_pcie_wr_conf(pp, bus, devfn, where, size, val);
	else {
		spear_dbi_write_reg(pp, where, size, val);
		ret = 0;
	}
	spin_unlock_irqrestore(&pp->conf_lock, flags);

	return ret;
}



static int spear13xx_pcie_rd_conf(struct pcie_port *pp, struct pci_bus *bus,
		u32 devfn, int where, int size, u32 *val)
{
	struct pcie_app_reg *app_reg = (struct pcie_app_reg *) pp->va_app_base;
	u32 address = (u32)pp->va_cfg0_base | (PCI_FUNC(devfn) << 16)
		| (where & 0xFFFC);

	writel((bus->number << 24) | (PCI_SLOT(devfn) << 19),
			&app_reg->pom_cfg0_addr_start);
	writel(readl(&app_reg->slv_armisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_armisc);
	if (bus->parent->number == pp->root_bus_nr)
		writel(readl(&app_reg->slv_armisc) |
				AXI_OP_TYPE_CONFIG_RDRW_TYPE0,
				&app_reg->slv_armisc);
	else
		writel(readl(&app_reg->slv_armisc) |
				AXI_OP_TYPE_CONFIG_RDRW_TYPE1,
				&app_reg->slv_armisc);
	udelay(1);
	*val = readl(address);
	if (size == 1)
		*val = (*val >> (8 * (where & 3))) & 0xff;
	else if (size == 2)
		*val = (*val >> (8 * (where & 3))) & 0xffff;

	writel(readl(&app_reg->slv_armisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_armisc);

	return PCIBIOS_SUCCESSFUL;
}

static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
			int size, u32 *val)
{
	struct pcie_port *pp = bus_to_port(bus->number);
	unsigned long flags;
	int ret;

	if (pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
		*val = 0xffffffff;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}

	spin_lock_irqsave(&pp->conf_lock, flags);
	if (bus->number != pp->root_bus_nr)
		ret = spear13xx_pcie_rd_conf(pp, bus, devfn, where, size, val);
	else {
		spear_dbi_read_reg(pp, where, size, val);
		ret = 0;
	}
	spin_unlock_irqrestore(&pp->conf_lock, flags);

	return ret;
}

static int spear13xx_pcie_wr_conf(struct pcie_port *pp, struct pci_bus *bus,
		u32 devfn, int where, int size, u32 val)
{
	int ret = PCIBIOS_SUCCESSFUL;
	struct pcie_app_reg *app_reg = (struct pcie_app_reg *) pp->va_app_base;
	u32 address = (u32)pp->va_cfg0_base | (PCI_FUNC(devfn) << 16)
			| (where & 0xFFFC);

	writel((bus->number << 24) | (PCI_SLOT(devfn) << 19),
			&app_reg->pom_cfg0_addr_start);
	writel(readl(&app_reg->slv_awmisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_awmisc);
	if (bus->parent->number == pp->root_bus_nr)
		writel(readl(&app_reg->slv_awmisc)
				| AXI_OP_TYPE_CONFIG_RDRW_TYPE0,
				&app_reg->slv_awmisc);
	else
		writel(readl(&app_reg->slv_awmisc)
				| AXI_OP_TYPE_CONFIG_RDRW_TYPE1,
				&app_reg->slv_awmisc);
	if (size == 4)
		writel(val, address);
	else if (size == 2)
		writew(val, address + (where & 2));
	else if (size == 1)
		writeb(val, address + (where & 3));
	else
		ret = PCIBIOS_BAD_REGISTER_NUMBER;
	writel(readl(&app_reg->slv_awmisc) & ~(AXI_OP_TYPE_MASK),
			&app_reg->slv_awmisc);
	return ret;
}

static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
			int where, int size, u32 val)
{
	struct pcie_port *pp = bus_to_port(bus->number);
	unsigned long flags;
	int ret;

	if (pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
		return PCIBIOS_DEVICE_NOT_FOUND;

	spin_lock_irqsave(&pp->conf_lock, flags);
	if (bus->number != pp->root_bus_nr)
		ret = spear13xx_pcie_wr_conf(pp, bus, devfn, where, size, val);
	else {
		spear_dbi_write_reg(pp, where, size, val);
		ret = 0;
	}
	spin_unlock_irqrestore(&pp->conf_lock, flags);

	return ret;
}






On Thu, Oct 21, 2010 at 5:55 PM, Matthew Wilcox <matthew@xxxxxx> wrote:
> On Thu, Oct 21, 2010 at 05:16:22PM +0530, Pratyush Anand wrote:
>> Hi All,
>>
>> I have developed support for a PCIE host controller on linux platform
>> for an SOC.
>>
>> It works well with PCIE devices (e.g.usb3.0 card, ethernet card, pcie
>> to sata )from various vendors.
>>
>> However, I am having problem in using any card where device is
>> connected below a bridge (class 0x0604).
>>
>> What ever bus number is programmed , cfg register value are from
>> bridge only not of downstream device.
>
> It would be helpful if you could post your code.  I suspect the problem is
> that you're telling the host bridge to generate CfgRd0 instead of CfgRd1.
>
> --
> Matthew Wilcox                          Intel Open Source Technology Centre
> "Bill, look, we understand that you're interested in selling us this
> operating system, but compare it to ours.  We can't possibly take such
> a retrograde step."
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux