On Sun, Oct 24, 2010 at 11:24 AM, Grant Grundler <grundler@xxxxxxxxxxxxxxxx> wrote: > 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. > I think so now. I have modified my read/write routine and I am no more able to access DS's cfg area if I generate cfg1(I am not sure if it still generates cfg1 correctly.) I will check it on analyser. It will give me quick fix. > 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? > > I will modify it. Will use readl only once. >> 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. > > I am still investigating this issue. Write is posted. So wmb() would have been correct option. But it does not help. >> 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? > If I do orring without clearing, then it might generate wrong values. > 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? > pcie_rd_conf checks whether, request is for RC (lets say Bus 0) or Downstream device (lets says bus1). If it is DS device then , spear13xx_pcie_rd_conf() checks whether it is for the first device below RC (cfg0) or next in the tree(cfg1). > 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