Joakim Tjernlund/Transmode wrote on 2012/07/21 18:11:32:
Kumar Gala [off-list ref] wrote on 2012/07/20 20:53:10:
quoted
On Jul 20, 2012, at 2:17 AM, Joakim Tjernlund wrote:
quoted
Hi Guys
I see that you have been hacking Freescale PCI before so I send this to you(and the list)
We are using PCIe(as RC) on P2010(basically a mpc85xx) and have PCI device that
started from user space (needs advance clock conf) so when linux boots there is
no device at all.
Trying to "hotplug" the device after it is enabled fails, no amount of recan/remove using
either fake or real hotplug makes a difference.
I found the cause eventually but I can't fix it properly as I known almost nothing about PCI.
Cause:
indirect_pci.c:indirect_read_config() tests for if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
and returns PCIBIOS_DEVICE_NOT_FOUND
PPC_INDIRECT_TYPE_NO_PCIE_LINK get set by fsl_pci.c (look for fsl_pcie_check_link) but is never cleared.
Clearing it as appropriate makes a small difference. If you
remove the RC and do a few of rescan's then the device appears.
Hacking some more, like so:
int fsl_pcie_check_link(struct pci_controller *hose)
{
u32 val;
early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
if (val < PCIE_LTSSM_L0)
return 1;
hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
return 0;
}
and then using it carefully(it is easy to make linux hang) in indirect_read_config():
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
u32 bus_no, reg;
if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
if (bus->number != hose->first_busno ||
devfn != 0) {
fsl_pcie_check_link(hose);
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
Now it works, just one rescan and the device appears!
This is a hack, I don't known what other trouble it can cause, I hope you can
sort this out.
How are you forcing the re-scan? We can see if we can add a re-check of the link state in that flow somewhere.
echo 1 > /sys/bus/pci/rescan
Why is that check important? Seems like some very ppc specific workaround for something.
quoted
Can you do a dump_stack() or something to get a call chain?
here?
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
u32 bus_no, reg;
static int first_dump;
if (!first_dump) {
dump_stack();
first_dump = 1;
}
...
I am not at work and and my board needs a reset button press to recover :(
Furthermore, my vacation starts next week, not sure I can get it fixed soon enough
So I managed to get someone to connect the BDI. Here is a dump according to the above:
Memory CAM mapping: 256/256 Mb, residual: 0Mb
Linux version 3.4.0+ (jocke@gentoo-jocke) (gcc version 4.5.3 (Gentoo 4.5.3-r2 p1.1, pie-0.4.7) ) #2088 PREEMPT Sat Jul 21 18:05:10 CEST 2012
bootconsole [udbg0] enabled
setup_arch: bootmem
p1010_rdb_setup_arch()
Call Trace:
[c0399e50] [c0006f28] show_stack+0x54/0x158 (unreliable)
[c0399e90] [c0019390] indirect_read_config+0x23c/0x250
[c0399ec0] [c017e630] pci_bus_read_config_byte+0x4c/0x94
[c0399ef0] [c000f4d4] early_read_config_byte+0x30/0x44
[c0399f10] [c0364524] fsl_add_bridge+0x118/0xa5c
[c0399f90] [c03655b4] p1010_rdb_setup_arch+0x8c/0xcc
[c0399fb0] [c0361850] setup_arch+0x1a8/0x1e8
[c0399fc0] [c035d558] start_kernel+0x80/0x2f0
[c0399ff0] [c00003ac] skpinv+0x298/0x2d4
Found FSL PCI host bridge at 0x00000000ff70a000. Firmware bus number: 0->1
PCI host bridge /pcie@ff70a000 ranges:
MEM 0x0000000080000000..0x000000009fffffff -> 0x0000000080000000
IO 0x00000000ffc00000..0x00000000ffc0ffff -> 0x0000000000000000
/pcie@ff70a000: PCICSRBAR @ 0xfff00000
So early_read_config_byte uses indirect_read_config so obviously you cannot
use early_read_config_xxx from within indirect_read_config as this gets you
into a nice recursion loop :)
Anyhow, I will be travelling for the better part of this week and will
have very limited Internet access.
Jocke
Joakim Tjernlund/Transmode wrote on 2012/07/21 18:11:32:
quoted
Kumar Gala [off-list ref] wrote on 2012/07/20 20:53:10:
quoted
On Jul 20, 2012, at 2:17 AM, Joakim Tjernlund wrote:
quoted
Hi Guys
I see that you have been hacking Freescale PCI before so I send this to you(and the list)
We are using PCIe(as RC) on P2010(basically a mpc85xx) and have PCI device that
started from user space (needs advance clock conf) so when linux boots there is
no device at all.
Trying to "hotplug" the device after it is enabled fails, no amount of recan/remove using
either fake or real hotplug makes a difference.
I found the cause eventually but I can't fix it properly as I known almost nothing about PCI.
Cause:
indirect_pci.c:indirect_read_config() tests for if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
and returns PCIBIOS_DEVICE_NOT_FOUND
PPC_INDIRECT_TYPE_NO_PCIE_LINK get set by fsl_pci.c (look for fsl_pcie_check_link) but is never cleared.
Clearing it as appropriate makes a small difference. If you
remove the RC and do a few of rescan's then the device appears.
Hacking some more, like so:
int fsl_pcie_check_link(struct pci_controller *hose)
{
u32 val;
early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
if (val < PCIE_LTSSM_L0)
return 1;
hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
return 0;
}
and then using it carefully(it is easy to make linux hang) in indirect_read_config():
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
u32 bus_no, reg;
if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
if (bus->number != hose->first_busno ||
devfn != 0) {
fsl_pcie_check_link(hose);
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
Now it works, just one rescan and the device appears!
This is a hack, I don't known what other trouble it can cause, I hope you can
sort this out.
How are you forcing the re-scan? We can see if we can add a re-check of the link state in that flow somewhere.
echo 1 > /sys/bus/pci/rescan
Why is that check important? Seems like some very ppc specific workaround for something.
quoted
Can you do a dump_stack() or something to get a call chain?
quoted
here?
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
u32 bus_no, reg;
static int first_dump;
if (!first_dump) {
dump_stack();
first_dump = 1;
}
...
I am not at work and and my board needs a reset button press to recover :(
Furthermore, my vacation starts next week, not sure I can get it fixed soon enough
So I managed to get someone to connect the BDI. Here is a dump according to the above:
Memory CAM mapping: 256/256 Mb, residual: 0Mb
Linux version 3.4.0+ (jocke@gentoo-jocke) (gcc version 4.5.3 (Gentoo 4.5.3-r2 p1.1, pie-0.4.7) ) #2088 PREEMPT Sat Jul 21 18:05:10 CEST 2012
bootconsole [udbg0] enabled
setup_arch: bootmem
p1010_rdb_setup_arch()
Call Trace:
[c0399e50] [c0006f28] show_stack+0x54/0x158 (unreliable)
[c0399e90] [c0019390] indirect_read_config+0x23c/0x250
[c0399ec0] [c017e630] pci_bus_read_config_byte+0x4c/0x94
[c0399ef0] [c000f4d4] early_read_config_byte+0x30/0x44
[c0399f10] [c0364524] fsl_add_bridge+0x118/0xa5c
[c0399f90] [c03655b4] p1010_rdb_setup_arch+0x8c/0xcc
[c0399fb0] [c0361850] setup_arch+0x1a8/0x1e8
[c0399fc0] [c035d558] start_kernel+0x80/0x2f0
[c0399ff0] [c00003ac] skpinv+0x298/0x2d4
Found FSL PCI host bridge at 0x00000000ff70a000. Firmware bus number: 0->1
PCI host bridge /pcie@ff70a000 ranges:
MEM 0x0000000080000000..0x000000009fffffff -> 0x0000000080000000
IO 0x00000000ffc00000..0x00000000ffc0ffff -> 0x0000000000000000
/pcie@ff70a000: PCICSRBAR @ 0xfff00000
So early_read_config_byte uses indirect_read_config so obviously you cannot
use early_read_config_xxx from within indirect_read_config as this gets you
into a nice recursion loop :)
Anyhow, I will be travelling for the better part of this week and will
have very limited Internet access.
Any ideas on this?
I think my hack will work in the general case too witch a small improvement:
indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
u32 bus_no, reg;
if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
if (bus->number != hose->first_busno ||
devfn != 0) {
fsl_pcie_check_link(hose);
if (!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK))
goto link_ok;
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
link_ok:
or we could opencode fsl_pcie_check_link directly here to avoid exporting the function
Jocke