大家好,我们在调试飞思卡尔的4in1编码器TW6865时遇到了难以解决的问题,希望大家给个意见和帮助;
在通过内核中System Type->Freescale MXC Implementations下的PCI Express选项
- [*] PCI Express support
- [ ] PCI Express EP mode in the IMX6 RC/EP interconnection system
- [ ] PCI Express RC mode in the IMX6 RC/EP interconnection system
- 在内核中通过补丁pcie_cap_patch.patch 向kernel中添加TW6865相关的驱动和配置;并在内核的选项选上tw68系列的encoder的编码器
- <*> Multimedia support --->
- [*] Video capture adapters --->
- Encoders, decoders, sensors and other helper chips --->
- <*> pcie TW68 video encoder
复制代码
启动之后,我们的log中可以看到pcie可以link up,也就是说link上pcie;
PMU: registered new PMU device of type 0
Static Power Management for Freescale i.MX6
wait mode is enabled for i.MX6
cpaddr = c0880000 suspend_iram_base=c091c000
PM driver module loaded
iMX6 PCIe PCIe RC mode imx_pcie_pltfm_probe entering.
PCIE: imx_pcie_pltfm_probe start link up.
IMX PCIe port: link up.
PCI: bus0: Fast back to back transfers disabled
liutest start fixup imx6dq pcie tw6869
pci 0000:01:00.0: Setting PCI class for tw6868 PCIe device
liutest END fixup imx6dq pcie tw6869
PCI: bus1: Fast back to back transfers disabled
pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff 64bit pref]
pci 0000:00:00.0: BAR 0: set to [mem 0x01000000-0x010fffff 64bit pref] (PCI address [0x1000000-0x10fffff])
pci 0000:00:00.0: BAR 9: assigned [mem 0x01100000-0x011fffff pref]
pci 0000:00:00.0: BAR 6: assigned [mem 0x01200000-0x0120ffff pref]
pci 0000:01:00.0: BAR 0: assigned [mem 0x01100000-0x01100fff pref]
pci 0000:01:00.0: BAR 0: set to [mem 0x01100000-0x01100fff pref] (PCI address [0x1100000-0x1100fff])
pci 0000:00:00.0: PCI bridge to [bus 01-01]
pci 0000:00:00.0: bridge window [io disabled]
pci 0000:00:00.0: bridge window [mem disabled]
pci 0000:00:00.0: bridge window [mem 0x01100000-0x011fffff pref]
liutest PCI: r->start =0x1000000 r->end =0x10fffff
IMX usb wakeup probe
add wake up source irq 75
IMX usb wakeup probe
从这段log中可以看到pcie在探测插槽上的设备时是找到了设备的,并且成功连接,但是我们在这之后,CPU却在运行到如下log的地方停住了;
.......
ARC USBOTG Device Controller driver (1 August 2005)
mousedev: PS/2 mouse device common for all mice
i2c-core: driver [isl29023] using legacy suspend method
i2c-core: driver [isl29023] using legacy resume method
snvs_rtc snvs_rtc.0: rtc core: registered snvs_rtc as rtc0
i2c /dev entries driver
Linux video capture interface: v2.00
TW6868_: v4l2 driver version 2.0.1 loaded
PCI register init called //【死在了这里,没有继续往下启动了】
跟踪内核中的运行到函数__pci_enable_device_flags(struct pci_dev *dev,resource_size_t flags)时在里面调用函数pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);时没有返回一直停留在这个函数里面了,但是CPU没有”死掉“,就是停在里面了,因为在我注释掉这个函数之后,程序可以正确的跑到printk(KERN_INFO "pos 4 : after PCI register init called\n");函数;
File:pci.c
- static int __pci_enable_device_flags(struct pci_dev *dev,resource_size_t flags)
- {
- int err;
- int i, bars = 0;
- /*
- * Power state could be unknown at this point, either due to a fresh
- * boot or a device removal call. So get the current power state
- * so that things like MSI message writing will behave as expected
- * (e.g. if the device really is in D0 at enable time).
- */
- if (dev->pm_cap) {
- u16 pmcsr;
- // add by huan.gong @ 2015-01-13
- printk(KERN_INFO "pos 3 : after PCI register init called\n");
- pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
- dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
- }
- // add by huan.gong @ 2015-01-13
- printk(KERN_INFO "pos 4 : after PCI register init called\n");
- if (atomic_add_return(1, &dev->enable_cnt) > 1)
- {
- // add by huan.gong @ 2015-01-13
- printk(KERN_INFO "pos 5 : after PCI register init called\n");
- return 0; /* already enabled */
- }
复制代码之后我又跟踪了函数pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);内联函数
- static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
- {
- return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
- }
- EXPORT_SYMBOL(pci_bus_read_config_word);
复制代码
为了提高性能这个函数最终的实现时宏
- #define PCI_OP_READ(size,type,len) \
- int pci_bus_read_config_##size \
- (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
- { \
- int res; \
- unsigned long flags; \
- u32 data = 0; \
- if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
- printk(KERN_INFO "::::lock irq\n");\
- raw_spin_lock_irqsave(&pci_lock, flags); \
- printk(KERN_INFO "::::read before\n");\
- res = bus->ops->read(bus, devfn, pos, len, &data); \
- printk(KERN_INFO "::::read after\n");\
- *value = (type)data; \
- raw_spin_unlock_irqrestore(&pci_lock, flags); \
- printk(KERN_INFO "::::unlock irq\n");\
- return res; \
- }
复制代码
#define PCI_OP_READ(size,type,len) \
int pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
{ \
int res; \
unsigned long flags; \
u32 data = 0; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
printk(KERN_INFO "::::lock irq\n");\
raw_spin_lock_irqsave(&pci_lock, flags); \
printk(KERN_INFO "::::read before\n");\
res = bus->ops->read(bus, devfn, pos, len, &data); \
printk(KERN_INFO "::::read after\n");\
*value = (type)data; \
raw_spin_unlock_irqrestore(&pci_lock, flags); \
printk(KERN_INFO "::::unlock irq\n");\
return res; \
}
最终,cpu是挂在了第39行的read函数里面,而这个是一个函数指针,是在驱动开发的过程中通过.read = XXXX()来指定的,如果结合我们前面分析的那部分应该是read(dev->bus, dev->devfn,dev->pm_cap + PCI_PM_CTRL,&pmcsr)其中dev就是pcie设备;也就是说在读取pcie的PCI_PM_CTRL控制字(16bit)时进去就没能出来,而原本读出来是要存入pmcsr的。
通过代码不难猜测出,是在去读取pcie电源相关配置字的时候除了问题。其实在这之前,我们可以是启动到内核加载DVFS module时挂掉的,后来卸载了patch之后,重新打上这个补丁,就变成这样了,而且用没有修改过的最原始的kernel来测试还是在PCI register init called..之后不动了.../欲哭无泪の
通过测试我们还看到了其他的log,在“挂起”之前,也有调用这个函数,只不过传进来的位置和要读取的长度不一样而已。
这可能是目前遇到的最难处理的问题,也不知道如何下手去处理,我们前期功能验证和测试的时候用的是成都嵌智捷科技的板子,后来我们的工程师开发的定制的板子,嵌智捷的板子上我们没有测试过PCIE,希望有相关经验的来帮忙分析一些,不胜感激.....提前来个万分感谢....