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


[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