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

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

 



On Thu, Oct 21, 2010 at 08:57:08PM +0530, Pratyush Anand wrote:
> 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.

My bet is that willy is right.

Can you get a PCI-E bus analyzer attached to see what transactions the 
PCI-E Bridge is generating on the secondary bus?


> 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);

Does reading app_reg->slv_armisc register have any side effects?
Is there any reason you can't cache this value and use the cached value
with the '|' expression?


> 	else
> 		writel(readl(&app_reg->slv_armisc) |
> 				AXI_OP_TYPE_CONFIG_RDRW_TYPE1,
> 				&app_reg->slv_armisc);
> 	udelay(1);
> 	*val = readl(address);

Why the udelay()?
Is the writel() a posted or non-posted write?
(ie does the CPU stall until the write completes or not?)
If the CPU does not stall (writes are "posted"), then the udelay() is
pointless and misleading.


> 	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);

Why clear those bits in the slv_armisc register?

Borrow a PCIe protocol analyzer for a week or two
and this would be easy to resolve.

> 	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;
> 	}

Why do both pcie_rd_conf() and spear13xx_pcie_rd_conf()
have to check the bus->number?

AFAIK, only the root control should need special handling
to setup up type0 or type1 config transactions on the PCIe bridge.
Or does this PCIe-PCIe bridge need SW support to correctly handle CFG space?


hth,
grant

> 	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
--
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