Let's go futher. 25.09.2013, 22:58, "Alex Ivanov" <gnidorah@xxxxxxxxx>: > 25.09.2013, 21:28, "Konrad Rzeszutek Wilk" <konrad.wilk@xxxxxxxxxx>: >> I took a look at the arch/parisc/kernel/pci-dma.c and I see that >> is mostly a flat platform. That is bus addresses == physical addresses. >> Unless it is an pclx or pclx2 CPU type (huh?) - if its it that >> then any calls to dma_alloc_coherent will map memory out of a pool. >> In essence it will look like a SWIOTLB bounce buffer. > arch/parisc/kernel/pci-dma.c: > ** PARISC 1.1 Dynamic DMA mapping support. > ** This implementation is for PA-RISC platforms that do not support > ** I/O TLBs (aka DMA address translation hardware). > > That's very old. PA-RISC 2.0 came into the game circa 1996. > PA-RISC 1.1 is 32-bit only and i even not sure whether these machines > had PCI bus. > > Only old boxes (PA7200 CPU and lower) cannot use dma_alloc_coherent() > (and forced to do syncs iirc). That's not our case. > And PA-RISC configs have 'Discontiguous Memory' choosen. >> But interestingly enough there is a lot of 'flush_kernel_dcache_range' >> call for every DMA operation. >> And I think the you need to do >> dma_sync_for_cpu call in the radeon_test_writeback for it to >> use the flush_kernel_dcache_range. I was correct regarding syncs. In our case (SBA IOMMU) dma_sync* calls are no-ops: sba_iommu.c: static struct hppa_dma_ops sba_ops = { ... .dma_sync_single_for_cpu = NULL, .dma_sync_single_for_device = NULL, .dma_sync_sg_for_cpu = NULL, .dma_sync_sg_for_device = NULL, } dma-mapping.h: dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { if(hppa_dma_ops->dma_sync_single_for_cpu) flush_kernel_dcache_range((unsigned long)vaddr, size); } So i'll skip doing the flush_kernel_dcache_range(). >> I don't know what the >> flush_kernel_dcache_range does thought so I could be wrong. > D-cache is a CPU cache (if they meant it). > Seems to be L1-level. There is an I-cache at same level. >> You are missing a translation here (you were comparing the virtual address >> to the bus address). I was thinking something along this: > Yes, this confused me. I've translated your suggestion literally :\ >> unsigned int pfn = page_to_pfn(ttm->pages[i]); >> dma_addr_t bus = gtt->ttm.dma_address[i]; >> void *va_bus, *va, *va_pfn; >> >> if ((pfn << PAGE_SHIFT) != bus) >> printk("Bus 0x%lx != PFN 0x%lx, bus, pfn << PAGE_SHIFT); /* OK, that means >> bus addresses are different */ >> >> va_bus = bus_to_virt(gtt->ttm.dma_address[i]); >> va_pfn = __va(pfn << PAGE_SHIFT); >> >> if (!virt_addr_valid(va_bus)) >> printk("va_bus (0x%lx) not good!\n", va_bus); >> if (!virt_addr_valid(va_pfn)) >> printk("va_pfn (0x%lx) not good!\n", va_pfn); >> >> /* We got VA for both bus -> va, and pfn -> va. Should be the >> same if bus and physical addresses are on the same namespace. */ >> if (va_bus != va_pfn) >> printk("va bus:%lx != va pfn: %lx\n", va_bus, va_pfn); >> >> /* Now that we have bus -> pa -> va (va_bus) try to go va_bus -> bus address. >> The bus address should be the same */ >> if (gtt->tmm.dma_address[i] != virt_to_bus(va_bus)) >> printk("bus->pa->va:%lx != bus->pa->va->ba: %lx\n", gtt->tmm.dma_address[i],virt_to_bus(va_bus)); Ok, slightly modified: struct page *page = ttm->pages[i]; unsigned long pfn = page_to_pfn(page); dma_addr_t bus = gtt->ttm.dma_address[i]; void *va_bus, *va, *va_pfn; BUG_ON(!pfn_valid(pfn)); //BUG_ON(!page_mapping(page)); // Leads to a kernel BUG /* Avoid floodage */ if (i % 100 == 0) { if ((pfn << PAGE_SHIFT) != bus) printk("Bus 0x%lx != PFN 0x%lx\n", bus, pfn << PAGE_SHIFT); /* OK, that means bus addresses are different */ va_bus = bus_to_virt(bus); va_pfn = __va(pfn << PAGE_SHIFT); if (!virt_addr_valid(va_bus)) printk("va_bus (0x%lx) not good!\n", va_bus); if (!virt_addr_valid(va_pfn)) printk("va_pfn (0x%lx) not good!\n", va_pfn); /* We got VA for both bus -> va, and pfn -> va. Should be the same if bus and physical addresses are on the same namespace. */ if (va_bus != va_pfn) printk("va bus: %lx != va pfn: %lx\n", va_bus, va_pfn); /* Now that we have bus -> pa -> va (va_bus) try to go va_bus -> bus address. The bus address should be the same */ if (bus != virt_to_bus(va_bus)) printk("bus->pa->va: %lx != bus->pa->va->ba: %lx\n", bus,virt_to_bus(va_bus)); } Output: Bus 0x40280000 != PFN 0x3e92d000 va_bus (0x80280000) not good! va bus: 80280000 != va pfn: 7e92d000 Bus 0x40281000 != PFN 0x3e930000 va_bus (0x80281000) not good! va bus: 80281000 != va pfn: 7e930000 ... va_bus is invalid. That's the reason i was getting a KF trying to read data behind it. >>> DRM_INFO("MISMATCH: %p != %p\n", va, (void *) virt_to_bus(va)); >>> /*DRM_INFO("CONTENTS: %x\n", *((uint32_t *)va));*/ // Leads to a Kernel Fault >> That is odd. I would have thought it would be usuable. >>> ... >>> } >>> >>> I'm getting the output: >>> >>> [drm] MISMATCH: 0000000080280000 != 0000000040280000 >> In theory that means the bus address that is programmed in (gtt->dma_address[i]) >> is 0000000040280000 (which is what virt_to_bus(va) should have resolved itself to). > Should resolved properly. I had a sane check of virt_to_bus(va) == gtt->ttm.dma_address[i] >> Tha you can't get access to 'va' (0000000080280000) is odd. One way to try to >> access it is to do: >> >> va = __va(page_to_pfn(ttm->pages[i]) << PAGE_SHIFT); >> DRM_INFO("CONTENTS: %x\n", *((uint32_t)va)); >> >> As that would get it via the page -> va. This way i get CONTENTS: 0 > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel