Message ID | 1583742206-29163-5-git-send-email-yangtiezhu@loongson.cn (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | Add basic support for Loongson 7A1000 bridge chip | expand |
---- 在 星期一, 2020-03-09 16:23:24 Tiezhu Yang <yangtiezhu@loongson.cn> 撰写 ---- > 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@loongson.cn> > --- > 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 > >
On 03/09/2020 04:44 PM, Jiaxun Yang wrote: > > ---- 在 星期一, 2020-03-09 16:23:24 Tiezhu Yang <yangtiezhu@loongson.cn> 撰写 ---- > > 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? Hi Jiaxun, Let me rethink it and find a proper way. > > > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > > --- > > 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. OK, I will do it. Thanks, Tiezhu Yang > > > +} > > + > > 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 > > > >
On Mon, Mar 09, 2020 at 04:23:24PM +0800, Tiezhu Yang wrote: > Implement __phys_to_dma() and __dma_to_phys() according to the > node id offset in 7A1000 DMA route config register. Can you just switch Loongson over to use the dma_pfn_offset field in struct device? I'd love to kill the __phys_to_dma and __dma_to_phys hooks wherever possible.
On 03/13/2020 04:24 PM, Christoph Hellwig wrote: > On Mon, Mar 09, 2020 at 04:23:24PM +0800, Tiezhu Yang wrote: >> Implement __phys_to_dma() and __dma_to_phys() according to the >> node id offset in 7A1000 DMA route config register. > Can you just switch Loongson over to use the dma_pfn_offset field in > struct device? I'd love to kill the __phys_to_dma and __dma_to_phys > hooks wherever possible. Hi Christoph, Thanks for your suggestion, I will refactor the code. Thanks, Tiezhu Yang
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; +} + 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 */
Implement __phys_to_dma() and __dma_to_phys() according to the node id offset in 7A1000 DMA route config register. Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> --- 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(-)