I worked on a very similar bug in the past, just with another ipq and another pcie card.
IMO, The issue is that cache coherency is not very well specified, and usually defined at the SoC/platform level.
Meaning, you could have the same arm core on 2 different SoCs, running the same driver with the same PCIe card and you will get corrupted data on the one where the PCIe controller‘s requests do not snoop the cpu cache.
Also, note that for both rx/tx to work, you need to invalidate on both sides: rx need to access the dram and not cache. tx need to verify that all was written to the dram before giving it to the hw.