---- 在 星期一, 2020-03-09 16:23:24 Tiezhu Yang <yangtiezhu@xxxxxxxxxxx> 撰写 ---- > Implement __phys_to_dma() and __dma_to_phys() according to the > node id offset in 7A1000 DMA route config register. That design shocked me a lot. And It is known that some firmware didn't configure HT Recieve window correctly to make it work. So probably for mainline kernel, just set DMA_MASK to limit LS7A DMA address to Node0 would be a better Option? > Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx> > --- > arch/mips/include/asm/mach-loongson64/boot_param.h | 1 + > arch/mips/loongson64/dma.c | 49 +++++++++++++++++++++- > arch/mips/loongson64/init.c | 13 ++++++ > 3 files changed, 61 insertions(+), 2 deletions(-) > > diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h > index 225a563..60e7a7e 100644 > --- a/arch/mips/include/asm/mach-loongson64/boot_param.h > +++ b/arch/mips/include/asm/mach-loongson64/boot_param.h > @@ -218,5 +218,6 @@ struct loongson_system_configuration { > extern struct efi_memory_map_loongson *loongson_memmap; > extern struct loongson_system_configuration loongson_sysconf; > extern struct board_devices *eboard; > +extern u32 node_id_offset; > > #endif > diff --git a/arch/mips/loongson64/dma.c b/arch/mips/loongson64/dma.c > index 5e86635..997c257 100644 > --- a/arch/mips/loongson64/dma.c > +++ b/arch/mips/loongson64/dma.c > @@ -2,24 +2,69 @@ > #include <linux/dma-direct.h> > #include <linux/init.h> > #include <linux/swiotlb.h> > +#include <boot_param.h> > > -dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) > +struct loongson_dma_ops { > + dma_addr_t (*phys_to_dma)(struct device *dev, phys_addr_t paddr); > + phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr); > +}; > + > +struct loongson_dma_ops loongson_dma; > + > +dma_addr_t __rs780e_phys_to_dma(struct device *dev, phys_addr_t paddr) > { > /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from > * Loongson-3's 48bit address space and embed it into 40bit */ > long nid = (paddr >> 44) & 0x3; > + > return ((nid << 44) ^ paddr) | (nid << 37); > } > > -phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) > +dma_addr_t __ls7a_phys_to_dma(struct device *dev, phys_addr_t paddr) > +{ > + long nid = (paddr >> 44) & 0x3; > + > + return ((nid << 44) ^ paddr) | (nid << (36 + node_id_offset)); > +} > + > + > +dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) > +{ > + return loongson_dma.phys_to_dma(dev, paddr); > +} > + > +phys_addr_t __rs780e_dma_to_phys(struct device *dev, dma_addr_t daddr) > { > /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from > * Loongson-3's 48bit address space and embed it into 40bit */ > long nid = (daddr >> 37) & 0x3; > + > return ((nid << 37) ^ daddr) | (nid << 44); > } > > +phys_addr_t __ls7a_dma_to_phys(struct device *dev, dma_addr_t daddr) > +{ > + long nid = (daddr >> (36 + node_id_offset)) & 0x3; > + > + return ((nid << (36 + node_id_offset)) ^ daddr) | (nid << 44); > +} > + > +phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) > +{ > + return loongson_dma.dma_to_phys(dev, daddr); > +} > + > void __init plat_swiotlb_setup(void) > { > swiotlb_init(1); > + > + if (strstr(eboard->name, "780E")) { > + loongson_dma.phys_to_dma = __rs780e_phys_to_dma; > + loongson_dma.dma_to_phys = __rs780e_dma_to_phys; > + } > + > + if (strstr(eboard->name, "7A1000")) { > + loongson_dma.phys_to_dma = __ls7a_phys_to_dma; > + loongson_dma.dma_to_phys = __ls7a_dma_to_phys; > + } > } > diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c > index 5ac1a0f..dd8463d 100644 > --- a/arch/mips/loongson64/init.c > +++ b/arch/mips/loongson64/init.c > @@ -12,6 +12,11 @@ > #include <asm/fw/fw.h> > > #include <loongson.h> > +#include <boot_param.h> > + > +#define NODE_ID_OFFSET_ADDR 0x90000E001001041CULL > + > +u32 node_id_offset; > > static void __init mips_nmi_setup(void) > { > @@ -23,6 +28,11 @@ static void __init mips_nmi_setup(void) > flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); > } > > +static void ls7a_early_config(void) > +{ > + node_id_offset = (*(u32 *)NODE_ID_OFFSET_ADDR >> 8) & 0x1F; Please avoid raw pointer. Use readl/writel instead. > +} > + > void __init prom_init(void) > { > fw_init_cmdline(); > @@ -32,6 +42,9 @@ void __init prom_init(void) > set_io_port_base((unsigned long) > ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); > > + if (strstr(eboard->name, "7A1000")) > + ls7a_early_config(); > + > prom_init_numa_memory(); > > /* Hardcode to CPU UART 0 */ > -- > 2.1.0 > >