riscv: Add DMA_COHERENT support for Allwinner D1
Subsystems (8)
v2 cover riscv: Add DMA_COHERENT support for Allwinner D1
From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add custom DMA_COHERENT attribute bits in PTE which not mentioned in spec.
Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has no conflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and setup custom PTE attributes in a global struct variable during boot stage. Also it needs define custom protection_map in linux/mm.
- cmo: We need deal with dma_sync & icache_sync & __vdso_icache_sync. In this patchset, I just show you how T-HEAD C9xx work, and seems Atish is working for the DMA infrustructure, please let me know the idea.
- soc: Add allwinner gmac driver & dts & Kconfig for sunxi test.
The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a 0x00200000 -e 0x00200000 -n Linux -d arch/riscv/boot/Image uImage
- Download newest opensbi [2], build with [3], and get fw_dynamic.bin
- Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot
partition of TF card.
- Plugin the TF card and power on D1.
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906 icache_sync
- Add Allwinner D1 dts & Kconfig & gmac for testing
- Add asid optimization for D1 usage
Guo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup _PAGE_CHG_MASK usage
riscv: pgtable: Add custom protection_map init
riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig option
liush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp use
arch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi create mode 100644 arch/riscv/mm/dma-mapping.c create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
Signature · 1 line
2.7.4
RFC PATCH v2 1/11 riscv: asid: Use global mappings for kernel pages
From: Guo Ren <[email protected]>
We map kernel pages into all addresses space, so they can be marked as global. This allows hardware to avoid flushing the kernel mappings when moving between address spaces.
--- arch/riscv/include/asm/pgtable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/riscv/include/asm/pgtable.h +2 -1
@@ -134,7 +134,8 @@ | _PAGE_WRITE \ | _PAGE_PRESENT \ | _PAGE_ACCESSED \ - | _PAGE_DIRTY) + | _PAGE_DIRTY \ + | _PAGE_GLOBAL)#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
Signature · 1 line
2.7.4
PATCH v5 1/3 riscv: Use global mappings for kernel pages
In reply to [email protected]From: Guo Ren <[email protected]>
We map kernel pages into all addresses space, so they can be marked as global. This allows hardware to avoid flushing the kernel mappings when moving between address spaces.
--- arch/riscv/include/asm/pgtable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/riscv/include/asm/pgtable.h +2 -1
@@ -134,7 +134,8 @@ | _PAGE_WRITE \ | _PAGE_PRESENT \ | _PAGE_ACCESSED \ - | _PAGE_DIRTY) + | _PAGE_DIRTY \ + | _PAGE_GLOBAL)#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
Signature · 1 line
2.7.4
PATCH v5 2/3 riscv: Add ASID-based tlbflushing methods
In reply to [email protected]From: Guo Ren <[email protected]>
Implement optimized version of the tlb flushing routines for systems using ASIDs. These are behind the use_asid_allocator static branch to not affect existing systems not using ASIDs.
--- arch/riscv/include/asm/mmu_context.h | 2 ++ arch/riscv/include/asm/tlbflush.h | 22 +++++++++++++++++ arch/riscv/mm/context.c | 2 +- arch/riscv/mm/tlbflush.c | 46 +++++++++++++++++++++++++++++++++--- 4 files changed, 68 insertions(+), 4 deletions(-)
arch/riscv/include/asm/mmu_context.h +2 -0
@@ -33,6 +33,8 @@ static inline int init_new_context(struct task_struct *tsk, return 0; } +DECLARE_STATIC_KEY_FALSE (use_asid_allocator); +#include <asm-generic/mmu_context.h> #endif /* _ASM_RISCV_MMU_CONTEXT_H */
arch/riscv/include/asm/tlbflush.h +22 -0
@@ -22,9 +22,31 @@ static inline void local_flush_tlb_page(unsigned long addr) {ALT_FLUSH_TLB_PAGE (__asm__ __volatile__ ("sfence.vma %0" : :"r" (addr) :"memory" )); } + +static inline void local_flush_tlb_all_asid (unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma x0, %0" + : + :"r" (asid) + :"memory" ); +} + +static inline void local_flush_tlb_range_asid (unsigned long start, +unsigned long size,unsigned long asid) +{ +unsigned long tmp, end =ALIGN (start + size,PAGE_SIZE ); + +for (tmp = start &PAGE_MASK ; tmp < end; tmp +=PAGE_SIZE ) { + __asm__ __volatile__ ("sfence.vma %0, %1" + : + :"r" (tmp),"r" (asid) + :"memory" ); + } +}#else /* CONFIG_MMU */ #define local_flush_tlb_all () do { } while (0)#define local_flush_tlb_page (addr) do { } while (0) +#define local_flush_tlb_range_asid (addr) do { } while (0)#endif /* CONFIG_MMU */ #if defined(CONFIG_SMP ) && defined(CONFIG_MMU )
arch/riscv/mm/context.c +1 -1
@@ -18,7 +18,7 @@#ifdef CONFIG_MMU -static DEFINE_STATIC_KEY_FALSE (use_asid_allocator); +DEFINE_STATIC_KEY_FALSE (use_asid_allocator);static unsigned long asid_bits;static unsigned long num_asids;
arch/riscv/mm/tlbflush.c +43 -3
67 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH V5 2/3] riscv: Add ASID-based tlbflushing methods
Quoted 9 lines · On Sun, Jun 06, 2021 at 09:03:58AM +0000, [email protected] wrote:
arch/riscv/include/asm/tlbflush.h +9
-0+static inline void local_flush_tlb_all_asid (unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma x0, %0" + : + :"r" (asid) + :"memory" ); +} + +static inline void local_flush_tlb_range_asid(unsigned long start,
arch/riscv/include/asm/tlbflush.h static inline void local_flush_tlb_page(unsigned long addr) · line 44
Quoted 10 lines
arch/riscv/include/asm/tlbflush.h +10
-0+ unsigned long size, unsigned long asid) +{ +unsigned long tmp, end =ALIGN (start + size,PAGE_SIZE ); + +for (tmp = start &PAGE_MASK ; tmp < end; tmp +=PAGE_SIZE ) { + __asm__ __volatile__ ("sfence.vma %0, %1" + : + :"r" (tmp),"r" (asid) + :"memory" ); + }
No need to expose these in a header.
Quoted 16 lines
arch/riscv/mm/tlbflush.c +16
-0+static void __sbi_tlb_flush_range_asid (struct cpumask *cmask, +unsigned long start, +unsigned long size, +unsigned long asid) +{ +struct cpumask hmask; +unsigned int cpuid; + +if (cpumask_empty (cmask)) +return ; + + cpuid =get_cpu (); + +if (cpumask_any_but (cmask, cpuid) >= nr_cpu_ids) { +if (size ==-1 ) +local_flush_tlb_all_asid (asid);
arch/riscv/mm/tlbflush.c static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start, · line 68
Quoted 10 lines
arch/riscv/mm/tlbflush.c +10
-0+else +local_flush_tlb_range_asid (start, size, asid); + }else { +riscv_cpuid_to_hartid_mask (cmask, &hmask); +sbi_remote_sfence_vma_asid (cpumask_bits (&hmask), + start, size, asid); + } + +put_cpu (); +}
Still no need to duplicate most of this logic. Also please document why this uses a different tradeoff for the flush all logic compared to the non-ASID path.
Quoted 20 lines
arch/riscv/mm/tlbflush.c +11
-2+void flush_tlb_mm (struct mm_struct *mm) { -__sbi_tlb_flush_range (mm_cpumask (mm),0 ,-1 ); +if (static_branch_unlikely (&use_asid_allocator)) +__sbi_tlb_flush_range_asid (mm_cpumask (mm),0 ,-1 , +atomic_long_read (&mm->context.id)); +else +__sbi_tlb_flush_range (mm_cpumask (mm),0 ,-1 ); }void flush_tlb_page (struct vm_area_struct *vma,unsigned long addr) { -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE ); +if (static_branch_unlikely (&use_asid_allocator)) +__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE , +atomic_long_read (&vma->vm_mm->context.id)); +else +__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE ); }
arch/riscv/mm/tlbflush.c static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start, · line 95
Quoted 10 lines
arch/riscv/mm/tlbflush.c +5
-1void flush_tlb_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) { -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), start, end - start); +if (static_branch_unlikely (&use_asid_allocator)) +__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), start, end - start, +atomic_long_read (&vma->vm_mm->context.id)); +else +__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), start, end - start);
Various overly long lines (which are trivially avoided when doing the right thing from the beginning).
RFC PATCH v2 2/11 riscv: asid: Add ASID-based tlbflushing methods
In reply to [email protected]From: Guo Ren <[email protected]>
Implement optimized version of the tlb flushing routines for systems using ASIDs. These are behind the use_asid_allocator static branch to not affect existing systems not using ASIDs.
--- arch/riscv/include/asm/mmu_context.h | 2 ++ arch/riscv/include/asm/tlbflush.h | 22 +++++++++++++++++ arch/riscv/mm/context.c | 2 +- arch/riscv/mm/tlbflush.c | 46 +++++++++++++++++++++++++++++++++--- 4 files changed, 68 insertions(+), 4 deletions(-)
arch/riscv/include/asm/mmu_context.h +2 -0
@@ -33,6 +33,8 @@ static inline int init_new_context(struct task_struct *tsk, return 0; } +DECLARE_STATIC_KEY_FALSE (use_asid_allocator); +#include <asm-generic/mmu_context.h> #endif /* _ASM_RISCV_MMU_CONTEXT_H */
arch/riscv/include/asm/tlbflush.h +22 -0
@@ -22,9 +22,31 @@ static inline void local_flush_tlb_page(unsigned long addr) {ALT_FLUSH_TLB_PAGE (__asm__ __volatile__ ("sfence.vma %0" : :"r" (addr) :"memory" )); } + +static inline void local_flush_tlb_all_asid (unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma x0, %0" + : + :"r" (asid) + :"memory" ); +} + +static inline void local_flush_tlb_range_asid (unsigned long start, +unsigned long size,unsigned long asid) +{ +unsigned long tmp, end =ALIGN (start + size,PAGE_SIZE ); + +for (tmp = start &PAGE_MASK ; tmp < end; tmp +=PAGE_SIZE ) { + __asm__ __volatile__ ("sfence.vma %0, %1" + : + :"r" (tmp),"r" (asid) + :"memory" ); + } +}#else /* CONFIG_MMU */ #define local_flush_tlb_all () do { } while (0)#define local_flush_tlb_page (addr) do { } while (0) +#define local_flush_tlb_range_asid (addr) do { } while (0)#endif /* CONFIG_MMU */ #if defined(CONFIG_SMP ) && defined(CONFIG_MMU )
arch/riscv/mm/context.c +1 -1
@@ -18,7 +18,7 @@#ifdef CONFIG_MMU -static DEFINE_STATIC_KEY_FALSE (use_asid_allocator); +DEFINE_STATIC_KEY_FALSE (use_asid_allocator);static unsigned long asid_bits;static unsigned long num_asids;
arch/riscv/mm/tlbflush.c +43 -3
67 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH v2 3/11 riscv: asid: Optimize tlbflush coding convention
In reply to [email protected]From: Guo Ren <[email protected]>
Passing the mm_struct as the first argument, as we can derive both the cpumask and asid from it instead of doing that in the callers.
But more importantly, the static branch check can be moved deeper into the code to avoid a lot of duplication.
Also add FIXME comment on the non-ASID code switches to a global flush once flushing more than a single page.
--- arch/riscv/mm/tlbflush.c | 91 ++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 50 deletions(-)
arch/riscv/mm/tlbflush.c +41 -50
@@ -12,56 +12,59 @@ void flush_tlb_all(void) }/* -* This function must not be called with cmask being null. +* This function must not be called with mm_cpumask(mm) being null. * Kernel may panic if cmask is NULL. */ -static void __sbi_tlb_flush_range (struct cpumask *cmask,unsigned long start, +static void __sbi_tlb_flush_range (struct mm_struct *mm, +unsigned long start,unsigned long size) { +struct cpumask *cmask =mm_cpumask (mm);struct cpumask hmask;unsigned int cpuid; +bool local;if (cpumask_empty (cmask))return ; cpuid =get_cpu (); -if (cpumask_any_but (cmask, cpuid) >= nr_cpu_ids) { -/* local cpu is the only cpu present in cpumask */ -if (size <=PAGE_SIZE ) -local_flush_tlb_page (start); -else -local_flush_tlb_all (); - }else { -riscv_cpuid_to_hartid_mask (cmask, &hmask); -sbi_remote_sfence_vma (cpumask_bits (&hmask), start, size); - } +/* +* check if the tlbflush needs to be sent to other CPUs, local +* cpu is the only cpu present in cpumask. +*/ + local = !(cpumask_any_but (cmask, cpuid) < nr_cpu_ids); -put_cpu (); -} - -static void __sbi_tlb_flush_range_asid (struct cpumask *cmask, -unsigned long start, -unsigned long size, -unsigned long asid) -{ -struct cpumask hmask; -unsigned int cpuid; - -if (cpumask_empty (cmask)) -return ; - - cpuid =get_cpu (); +if (static_branch_likely (&use_asid_allocator)) { +unsigned long asid =atomic_long_read (&mm->context.id); -if (cpumask_any_but (cmask, cpuid) >= nr_cpu_ids) { -if (size ==-1 ) -local_flush_tlb_all_asid (asid); -else -local_flush_tlb_range_asid (start, size, asid); +if (likely (local)) { +if (size ==-1 ) +local_flush_tlb_all_asid (asid); +else +local_flush_tlb_range_asid (start, size, asid); + }else { +riscv_cpuid_to_hartid_mask (cmask, &hmask); +sbi_remote_sfence_vma_asid (cpumask_bits (&hmask), + start, size, asid); + } }else { -riscv_cpuid_to_hartid_mask (cmask, &hmask); -sbi_remote_sfence_vma_asid (cpumask_bits (&hmask), - start, size, asid); +if (likely (local)) { +/* +* FIXME: The non-ASID code switches to a global flush +* once flushing more than a single page. It's made by +* commit 6efb16b1d551 (RISC-V: Issue a tlb page flush +* if possible). +*/ +if (size <=PAGE_SIZE ) +local_flush_tlb_page (start); +else +local_flush_tlb_all (); + }else { +riscv_cpuid_to_hartid_mask (cmask, &hmask); +sbi_remote_sfence_vma (cpumask_bits (&hmask), + start, size); + } }put_cpu ();
@@ -69,28 +72,16 @@ static void __sbi_tlb_flush_range_asid(struct cpumask *cmask,void flush_tlb_mm (struct mm_struct *mm) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (mm),0 ,-1 , -atomic_long_read (&mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (mm),0 ,-1 ); +__sbi_tlb_flush_range (mm,0 ,-1 ); }void flush_tlb_page (struct vm_area_struct *vma,unsigned long addr) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE , -atomic_long_read (&vma->vm_mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE ); +__sbi_tlb_flush_range (vma->vm_mm, addr,PAGE_SIZE ); }void flush_tlb_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), start, end - start, -atomic_long_read (&vma->vm_mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), start, end - start); +__sbi_tlb_flush_range (vma->vm_mm, start, end - start); }
Signature · 1 line
2.7.4
PATCH v5 3/3 riscv: tlbflush: Optimize coding convention
In reply to [email protected]From: Guo Ren <[email protected]>
Passing the mm_struct as the first argument, as we can derive both the cpumask and asid from it instead of doing that in the callers.
But more importantly, the static branch check can be moved deeper into the code to avoid a lot of duplication.
Also add FIXME comment on the non-ASID code switches to a global flush once flushing more than a single page.
--- arch/riscv/mm/tlbflush.c | 91 ++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 50 deletions(-)
arch/riscv/mm/tlbflush.c +41 -50
@@ -12,56 +12,59 @@ void flush_tlb_all(void) }/* -* This function must not be called with cmask being null. +* This function must not be called with mm_cpumask(mm) being null. * Kernel may panic if cmask is NULL. */ -static void __sbi_tlb_flush_range (struct cpumask *cmask,unsigned long start, +static void __sbi_tlb_flush_range (struct mm_struct *mm, +unsigned long start,unsigned long size) { +struct cpumask *cmask =mm_cpumask (mm);struct cpumask hmask;unsigned int cpuid; +bool local;if (cpumask_empty (cmask))return ; cpuid =get_cpu (); -if (cpumask_any_but (cmask, cpuid) >= nr_cpu_ids) { -/* local cpu is the only cpu present in cpumask */ -if (size <=PAGE_SIZE ) -local_flush_tlb_page (start); -else -local_flush_tlb_all (); - }else { -riscv_cpuid_to_hartid_mask (cmask, &hmask); -sbi_remote_sfence_vma (cpumask_bits (&hmask), start, size); - } +/* +* check if the tlbflush needs to be sent to other CPUs, local +* cpu is the only cpu present in cpumask. +*/ + local = !(cpumask_any_but (cmask, cpuid) < nr_cpu_ids); -put_cpu (); -} - -static void __sbi_tlb_flush_range_asid (struct cpumask *cmask, -unsigned long start, -unsigned long size, -unsigned long asid) -{ -struct cpumask hmask; -unsigned int cpuid; - -if (cpumask_empty (cmask)) -return ; - - cpuid =get_cpu (); +if (static_branch_likely (&use_asid_allocator)) { +unsigned long asid =atomic_long_read (&mm->context.id); -if (cpumask_any_but (cmask, cpuid) >= nr_cpu_ids) { -if (size ==-1 ) -local_flush_tlb_all_asid (asid); -else -local_flush_tlb_range_asid (start, size, asid); +if (likely (local)) { +if (size ==-1 ) +local_flush_tlb_all_asid (asid); +else +local_flush_tlb_range_asid (start, size, asid); + }else { +riscv_cpuid_to_hartid_mask (cmask, &hmask); +sbi_remote_sfence_vma_asid (cpumask_bits (&hmask), + start, size, asid); + } }else { -riscv_cpuid_to_hartid_mask (cmask, &hmask); -sbi_remote_sfence_vma_asid (cpumask_bits (&hmask), - start, size, asid); +if (likely (local)) { +/* +* FIXME: The non-ASID code switches to a global flush +* once flushing more than a single page. It's made by +* commit 6efb16b1d551 (RISC-V: Issue a tlb page flush +* if possible). +*/ +if (size <=PAGE_SIZE ) +local_flush_tlb_page (start); +else +local_flush_tlb_all (); + }else { +riscv_cpuid_to_hartid_mask (cmask, &hmask); +sbi_remote_sfence_vma (cpumask_bits (&hmask), + start, size); + } }put_cpu ();
@@ -69,28 +72,16 @@ static void __sbi_tlb_flush_range_asid(struct cpumask *cmask,void flush_tlb_mm (struct mm_struct *mm) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (mm),0 ,-1 , -atomic_long_read (&mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (mm),0 ,-1 ); +__sbi_tlb_flush_range (mm,0 ,-1 ); }void flush_tlb_page (struct vm_area_struct *vma,unsigned long addr) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE , -atomic_long_read (&vma->vm_mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), addr,PAGE_SIZE ); +__sbi_tlb_flush_range (vma->vm_mm, addr,PAGE_SIZE ); }void flush_tlb_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) { -if (static_branch_unlikely (&use_asid_allocator)) -__sbi_tlb_flush_range_asid (mm_cpumask (vma->vm_mm), start, end - start, -atomic_long_read (&vma->vm_mm->context.id)); -else -__sbi_tlb_flush_range (mm_cpumask (vma->vm_mm), start, end - start); +__sbi_tlb_flush_range (vma->vm_mm, start, end - start); }
Signature · 1 line
2.7.4
RFC PATCH v2 4/11 riscv: pgtable: Fixup _PAGE_CHG_MASK usage
In reply to [email protected]From: Guo Ren <[email protected]>
We should masks all attributes BITS first, and then using '>> _PAGE_PFN_SHIFT' to get the final PFN value.
Adding '& _PAGE_CHG_MASK' makes the code semantics more accurate.
--- arch/riscv/include/asm/pgtable-64.h | 8 +++++--- arch/riscv/include/asm/pgtable.h | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-)
arch/riscv/include/asm/pgtable-64.h +5 -3
@@ -62,12 +62,14 @@ static inline void pud_clear(pud_t *pudp)static inline unsigned long pud_page_vaddr (pud_t pud) { -return (unsigned long )pfn_to_virt (pud_val (pud) >> _PAGE_PFN_SHIFT); +return (unsigned long )pfn_to_virt ( + (pud_val (pud) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT); }static inline struct page *pud_page (pud_t pud) { -return pfn_to_page (pud_val (pud) >> _PAGE_PFN_SHIFT); +return pfn_to_page ( + (pud_val (pud) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT); }static inline pmd_t pfn_pmd (unsigned long pfn,pgprot_t prot)
@@ -77,7 +79,7 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)static inline unsigned long _pmd_pfn (pmd_t pmd) { -return pmd_val (pmd) >> _PAGE_PFN_SHIFT; +return (pmd_val (pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT; }#define pmd_ERROR (e) \
arch/riscv/include/asm/pgtable.h +3 -3
@@ -217,12 +217,12 @@ static inline unsigned long _pgd_pfn(pgd_t pgd)static inline struct page *pmd_page (pmd_t pmd) { -return pfn_to_page (pmd_val (pmd) >> _PAGE_PFN_SHIFT); +return pfn_to_page ((pmd_val (pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT); }static inline unsigned long pmd_page_vaddr (pmd_t pmd) { -return (unsigned long )pfn_to_virt (pmd_val (pmd) >> _PAGE_PFN_SHIFT); +return (unsigned long )pfn_to_virt ((pmd_val (pmd) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT); }static inline pte_t pmd_pte (pmd_t pmd)
@@ -233,7 +233,7 @@ static inline pte_t pmd_pte(pmd_t pmd)/* Yields the page frame number (PFN) of a page table entry */ static inline unsigned long pte_pfn (pte_t pte) { -return (pte_val (pte) >> _PAGE_PFN_SHIFT); +return ((pte_val (pte) & _PAGE_CHG_MASK) >> _PAGE_PFN_SHIFT); }#define pte_page (x) pfn_to_page(pte_pfn(x))
Signature · 1 line
2.7.4
RFC PATCH v2 5/11 riscv: pgtable: Add custom protection_map init
In reply to [email protected]From: Guo Ren <[email protected]>
Some RISC-V CPU vendors have defined their own PTE attributes to solve non-coherent DMA bus problems. That makes _P/SXXX definitions contain global variables which could be initialized at the early boot stage before setup_vm.
This patch is similar to 316d097c4cd4 (x86/pti: Filter at vma->vm_page_prot population) which give a choice for arch custom implementation.
--- arch/riscv/Kconfig | 4 ++++ arch/riscv/mm/init.c | 22 ++++++++++++++++++++++ mm/mmap.c | 4 ++++ 3 files changed, 30 insertions(+)
arch/riscv/Kconfig +4 -0
@@ -25,6 +25,7 @@ config RISCV select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_KCOV select ARCH_HAS_MMIOWB + select ARCH_HAS_PROTECTION_MAP_INIT select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_MEMORY
@@ -198,6 +199,9 @@ config GENERIC_HWEIGHT config FIX_EARLYCON_MEM def_bool MMU +config ARCH_HAS_PROTECTION_MAP_INIT + def_bool y + config PGTABLE_LEVELS int default 3 if 64BIT
arch/riscv/mm/init.c +22 -0
@@ -496,6 +496,26 @@ static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size) }#endif +static void __init setup_protection_map (void ) +{ + protection_map[0 ] = __P000; + protection_map[1 ] = __P001; + protection_map[2 ] = __P010; + protection_map[3 ] = __P011; + protection_map[4 ] = __P100; + protection_map[5 ] = __P101; + protection_map[6 ] = __P110; + protection_map[7 ] = __P111; + protection_map[8 ] = __S000; + protection_map[9 ] = __S001; + protection_map[10 ] = __S010; + protection_map[11 ] = __S011; + protection_map[12 ] = __S100; + protection_map[13 ] = __S101; + protection_map[14 ] = __S110; + protection_map[15 ] = __S111; +} + asmlinkage void __init setup_vm(uintptr_t dtb_pa) {uintptr_t __maybe_unused pa;
@@ -504,6 +524,8 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)pmd_t fix_bmap_spmd, fix_bmap_epmd;#endif +setup_protection_map (); +#ifdef CONFIG_XIP_KERNEL xiprom = (uintptr_t )CONFIG_XIP_PHYS_ADDR ; xiprom_sz = (uintptr_t )(&_exiprom) - (uintptr_t )(&_xiprom);
mm/mmap.c +4 -0
@@ -100,10 +100,14 @@ static void unmap_region(struct mm_struct *mm,* w: (no) no * x: (yes) yes */ +#ifdef CONFIG_ARCH_HAS_PROTECTION_MAP_INIT +pgprot_t protection_map[16 ]__ro_after_init ; +#else pgprot_t protection_map[16 ]__ro_after_init = { __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +#endif #ifndef CONFIG_ARCH_HAS_FILTER_PGPROT static inline pgprot_t arch_filter_pgprot (pgprot_t prot)
Signature · 1 line
2.7.4
RFC PATCH v2 6/11 riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
In reply to [email protected]From: Guo Ren <[email protected]>
The dma-noncoherent SOCs need different virtual memory mappings with different attributes:
- noncached + Strong Order (for IO/DMA descriptor)
- noncached + Weak Order (for writecombine usage, eg: frame buffer)
All above base on PTE attributes by MMU hardware. That means address attributes are determined by PTE entry, not PMA. RISC-V soc vendors have defined their own custom PTE attributes for dma-noncoherency.
--- arch/riscv/include/asm/pgtable-bits.h | 20 +++++++++++++++++++- arch/riscv/include/asm/pgtable.h | 11 ++++------- arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/soc.c | 22 ++++++++++++++++++++++ arch/riscv/mm/init.c | 4 ++++ 6 files changed, 51 insertions(+), 8 deletions(-)
arch/riscv/include/asm/pgtable-bits.h +19 -1
@@ -24,6 +24,11 @@#define _PAGE_DIRTY (1 << 7)/* Set by hardware on any write */ #define _PAGE_SOFT (1 << 8)/* Reserved for software */ +#define _PAGE_DMA_MASK __riscv_custom_pte.mask +#define _PAGE_DMA_CACHE __riscv_custom_pte.cache +#define _PAGE_DMA_IO __riscv_custom_pte.io +#define _PAGE_DMA_WC __riscv_custom_pte.wc +#define _PAGE_SPECIAL _PAGE_SOFT#define _PAGE_TABLE _PAGE_PRESENT
@@ -35,9 +40,22 @@#define _PAGE_PFN_SHIFT 10 +#ifndef __ASSEMBLY__ + +struct riscv_custom_pte { +unsigned long cache; +unsigned long mask; +unsigned long io; +unsigned long wc; +}; + +extern struct riscv_custom_pte __riscv_custom_pte; +/* Set of bits to preserve across pte_modify() */ #define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \ _PAGE_WRITE | _PAGE_EXEC | \ - _PAGE_USER | _PAGE_GLOBAL)) + _PAGE_USER | _PAGE_GLOBAL | \ + _PAGE_DMA_MASK)) +#endif #endif /* _ASM_RISCV_PGTABLE_BITS_H */
arch/riscv/include/asm/pgtable.h +4 -7
@@ -114,7 +114,7 @@#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)/* Page protection bits */ -#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER) +#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER | _PAGE_DMA_CACHE)#define PAGE_NONE __pgprot(_PAGE_PROT_NONE)#define PAGE_READ __pgprot(_PAGE_BASE | _PAGE_READ)
@@ -135,7 +135,8 @@ | _PAGE_PRESENT \ | _PAGE_ACCESSED \ | _PAGE_DIRTY \ - | _PAGE_GLOBAL) + | _PAGE_GLOBAL \ + | _PAGE_DMA_CACHE)#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
@@ -145,11 +146,7 @@#define PAGE_TABLE __pgprot(_PAGE_TABLE) -/* -* The RISC-V ISA doesn't yet specify how to query or modify PMAs, so we can't -* change the properties of memory regions. -*/ -#define _PAGE_IOREMAP _PAGE_KERNEL +#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_DMA_MASK) | _PAGE_DMA_IO)extern pgd_t swapper_pg_dir[];
arch/riscv/include/asm/soc.h +1 -0
@@ -17,6 +17,7 @@ = { .compatible = compat, .data = fn }void soc_early_init (void ); +void soc_setup_vm (void );extern unsigned long __soc_early_init_table_start;extern unsigned long __soc_early_init_table_end;
arch/riscv/include/asm/vendorid_list.h +1 -0
@@ -6,5 +6,6 @@#define ASM_VENDOR_LIST_H #define SIFIVE_VENDOR_ID 0x489 +#define THEAD_VENDOR_ID 0x401#endif
arch/riscv/kernel/soc.c +22 -0
@@ -3,8 +3,10 @@* Copyright (C) 2020 Western Digital Corporation or its affiliates. */ #include <linux/init.h> +#include <linux/mm.h> #include <linux/libfdt.h> #include <linux/pgtable.h> +#include <asm/image.h> #include <asm/soc.h> /*
@@ -26,3 +28,23 @@ void __init soc_early_init(void) } } } + +static void __init thead_init (void ) +{ + __riscv_custom_pte.cache =0x7000000000000000 ; + __riscv_custom_pte.mask =0xf800000000000000 ; + __riscv_custom_pte.io =BIT (63 ); + __riscv_custom_pte.wc =0 ; +} + +void __init soc_setup_vm (void ) +{ +unsigned long vendor_id = + ((struct riscv_image_header *)(&_start))->res1; + +switch (vendor_id) { +case THEAD_VENDOR_ID : +thead_init (); +break ; + } +};
arch/riscv/mm/init.c +4 -0
@@ -524,6 +524,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)pmd_t fix_bmap_spmd, fix_bmap_epmd;#endif +soc_setup_vm ();setup_protection_map ();#ifdef CONFIG_XIP_KERNEL
@@ -911,3 +912,6 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, return vmemmap_populate_basepages(start, end, node, NULL); }#endif + +struct riscv_custom_pte __riscv_custom_pte__ro_after_init ; +EXPORT_SYMBOL (__riscv_custom_pte);
Signature · 1 line
2.7.4
Re: [RFC PATCH v2 06/11] riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
NAK, no SOC must ever mess with pagetable attributes.
Re: [RFC PATCH v2 06/11] riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
Quoted 2 lines · Christoph Hellwig
NAK, no SOC must ever mess with pagetable attributes.
I don't think it messes with page table attributes. _PAGE_BASE contains variable won't cause any problem.
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 06/11] riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
In reply to [email protected]Στις 2021-06-06 12:04, [email protected] έγραψε:
Quoted 8 lines
From: Guo Ren <[email protected]>
The dma-noncoherent SOCs need different virtual memory mappings with different attributes:
- noncached + Strong Order (for IO/DMA descriptor)
- noncached + Weak Order (for writecombine usage, eg: frame buffer)
Quoted 5 lines
All above base on PTE attributes by MMU hardware. That means address attributes are determined by PTE entry, not PMA. RISC-V soc vendors have defined their own custom PTE attributes for dma-noncoherency.
This patch violates the Privilege Spec section 4.4.1 that clearly states:
"Bits63–54 are reserved for future standard use and must be zeroed by software for forward compatibility"
Standard use means that valid values can only be defined by the Priv. Spec, not by the vendor (otherwise they'd be marked as "custom use" or "platform use"), and since they "must" be zeroed by software we 'll be violating the Privilege Spec if we do otherwise.
Re: [RFC PATCH v2 06/11] riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
Quoted 9 lines · Nick Kossifidis
This patch violates the Privilege Spec section 4.4.1 that clearly states:
"Bits63–54 are reserved for future standard use and must be zeroed by software for forward compatibility"
Standard use means that valid values can only be defined by the Priv. Spec, not by the vendor (otherwise they'd be marked as "custom use" or "platform use"), and since they "must" be zeroed by software we 'll be violating the Privilege Spec if we do otherwise.
Yes, that is why I think it is a no-go.
RFC PATCH v2 7/11 riscv: cmo: Add dma-noncoherency support
In reply to [email protected]From: Guo Ren <[email protected]>
To support DMA device in a non-coherent interconnect SOC system, we need the below facilities:
- Changing a virtual memory mapping region attributes from cacheable to noncache + strong order which used in DMA descriptors.
- Add noncache + weakorder virtual memory attributes for dma mapping.
- Syncing the cache with memory before DMA start and after DMA end with vendor custom CMO instructions.
This patch enables linux kernel generic dma-noncoherency infrastructure and introduces new sbi_ecall API for dma_sync.
@@ -27,6 +27,7 @@ enum sbi_ext_id {
+ SBI_EXT_DMA = 0xAB150401,
--- arch/riscv/Kconfig | 5 ++++ arch/riscv/include/asm/pgtable.h | 26 ++++++++++++++++++++ arch/riscv/include/asm/sbi.h | 15 ++++++++++++ arch/riscv/kernel/sbi.c | 19 ++++++++++++++ arch/riscv/mm/Makefile | 1 + arch/riscv/mm/dma-mapping.c | 53 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+) create mode 100644 arch/riscv/mm/dma-mapping.c
arch/riscv/Kconfig +5 -0
@@ -20,6 +20,10 @@ config RISCV select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_WX + select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE
@@ -43,6 +47,7 @@ config RISCV select CLONE_BACKWARDS select CLINT_TIMER if !MMU select COMMON_CLK + select DMA_DIRECT_REMAP select EDAC_SUPPORT select GENERIC_ARCH_TOPOLOGY if SMP select GENERIC_ATOMIC64 if !64BIT
arch/riscv/include/asm/pgtable.h +26 -0
@@ -462,6 +462,32 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,return ptep_test_and_clear_young (vma, address, ptep); } +#define pgprot_noncached pgprot_noncached +static inline pgprot_t pgprot_noncached (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_IO; + +return __pgprot (prot); +} + +#define pgprot_writecombine pgprot_writecombine +static inline pgprot_t pgprot_writecombine (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_WC; + +return __pgprot (prot); +} + +#define __HAVE_PHYS_MEM_ACCESS_PROT +extern pgprot_t phys_mem_access_prot (struct file *file,unsigned long pfn, +unsigned long size,pgprot_t vma_prot); +/* * Encode and decode a swap entry *
arch/riscv/include/asm/sbi.h +15 -0
@@ -27,6 +27,7 @@ enum sbi_ext_id {SBI_EXT_IPI =0x735049 ,SBI_EXT_RFENCE =0x52464E43 ,SBI_EXT_HSM =0x48534D , + SBI_EXT_DMA = 0xAB150401, }; enum sbi_ext_base_fid {
@@ -63,6 +64,17 @@ enum sbi_ext_hsm_fid { SBI_EXT_HSM_HART_STATUS, }; +enum sbi_ext_dma_fid { +SBI_DMA_SYNC =0 , +}; + +enum sbi_dma_sync_data_direction { +SBI_DMA_BIDIRECTIONAL =0 , +SBI_DMA_TO_DEVICE =1 , +SBI_DMA_FROM_DEVICE =2 , +SBI_DMA_NONE =3 , +}; +enum sbi_hsm_hart_status {SBI_HSM_HART_STATUS_STARTED =0 ,SBI_HSM_HART_STATUS_STOPPED ,
@@ -128,6 +140,9 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,unsigned long size, unsigned long asid);int sbi_probe_extension (int ext); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir);/* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1 (void )
arch/riscv/kernel/sbi.c +19 -0
@@ -521,6 +521,25 @@ int sbi_probe_extension(int extid) }EXPORT_SYMBOL (sbi_probe_extension); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir) +{ +#if 0 +sbi_ecall (SBI_EXT_DMA ,SBI_DMA_SYNC , start, size, dir, +0 ,0 ,0 ); +#else +/* Just for try, it should be in sbi ecall and will be removed before merged */ + register unsigned long i asm("a0") = start & ~(L1_CACHE_BYTES - 1); + +for (; i <ALIGN (start + size,L1_CACHE_BYTES ); i +=L1_CACHE_BYTES ) + __asm__ __volatile__(".long 0x02b5000b" ); + + __asm__ __volatile__(".long 0x01b0000b" ); +#endif +} +EXPORT_SYMBOL (sbi_dma_sync); +static long __sbi_base_ecall (int fid) {struct sbiret ret;
arch/riscv/mm/Makefile +1 -0
@@ -13,6 +13,7 @@ obj-y += extable.o obj-$(CONFIG_MMU) += fault.o pageattr.o obj-y += cacheflush.o obj-y += context.o +obj-y += dma-mapping.o ifeq ($(CONFIG_MMU),y) obj-$(CONFIG_SMP) += tlbflush.o
arch/riscv/mm/dma-mapping.c new file +53 -0
53 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [RFC PATCH v2 07/11] riscv: cmo: Add dma-noncoherency support
Quoted 151 lines · On 2021/6/6 17:04, [email protected] wrote:
From: Guo Ren <[email protected]>
To support DMA device in a non-coherent interconnect SOC system, we need the below facilities:
- Changing a virtual memory mapping region attributes from cacheable to noncache + strong order which used in DMA descriptors.
- Add noncache + weakorder virtual memory attributes for dma mapping.
- Syncing the cache with memory before DMA start and after DMA end with vendor custom CMO instructions.This patch enables linux kernel generic dma-noncoherency infrastructure and introduces new
sbi_ecallAPI fordma_sync.arch/riscv/include/asm/sbi.h +1
-0@@ -27,6 +27,7 @@ enum sbi_ext_id { + SBI_EXT_DMA = 0xAB150401,Signed-off-by Guo Ren <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Anup Patel <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Drew Fustini <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>--- arch/riscv/Kconfig | 5 ++++ arch/riscv/include/asm/pgtable.h | 26 ++++++++++++++++++++ arch/riscv/include/asm/sbi.h | 15 ++++++++++++ arch/riscv/kernel/sbi.c | 19 ++++++++++++++ arch/riscv/mm/Makefile | 1 + arch/riscv/mm/dma-mapping.c | 53 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+) create mode 100644 arch/riscv/mm/dma-mapping.carch/riscv/Kconfig +5
-0@@ -20,6 +20,10 @@ config RISCV select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_WX + select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE@@ -43,6 +47,7 @@ config RISCV select CLONE_BACKWARDS select CLINT_TIMER if !MMU select COMMON_CLK + select DMA_DIRECT_REMAP select EDAC_SUPPORT select GENERIC_ARCH_TOPOLOGY if SMP select GENERIC_ATOMIC64 if !64BITarch/riscv/include/asm/pgtable.h +26
-0@@ -462,6 +462,32 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,return ptep_test_and_clear_young (vma, address, ptep); } +#define pgprot_noncached pgprot_noncached +static inline pgprot_t pgprot_noncached (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_IO; + +return __pgprot (prot); +} + +#define pgprot_writecombine pgprot_writecombine +static inline pgprot_t pgprot_writecombine (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_WC; + +return __pgprot (prot); +} + +#define __HAVE_PHYS_MEM_ACCESS_PROT +extern pgprot_t phys_mem_access_prot (struct file *file,unsigned long pfn, +unsigned long size,pgprot_t vma_prot); +/* * Encode and decode a swap entry * arch/riscv/include/asm/sbi.h +15
-0@@ -27,6 +27,7 @@ enum sbi_ext_id {SBI_EXT_IPI =0x735049 ,SBI_EXT_RFENCE =0x52464E43 ,SBI_EXT_HSM =0x48534D , + SBI_EXT_DMA = 0xAB150401, }; enum sbi_ext_base_fid {@@ -63,6 +64,17 @@ enum sbi_ext_hsm_fid { SBI_EXT_HSM_HART_STATUS, }; +enum sbi_ext_dma_fid { +SBI_DMA_SYNC =0 , +}; + +enum sbi_dma_sync_data_direction { +SBI_DMA_BIDIRECTIONAL =0 , +SBI_DMA_TO_DEVICE =1 , +SBI_DMA_FROM_DEVICE =2 , +SBI_DMA_NONE =3 , +}; +enum sbi_hsm_hart_status {SBI_HSM_HART_STATUS_STARTED =0 ,SBI_HSM_HART_STATUS_STOPPED ,@@ -128,6 +140,9 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,unsigned long size, unsigned long asid);int sbi_probe_extension (int ext); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir);/* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1 (void )arch/riscv/kernel/sbi.c +4
-0@@ -521,6 +521,25 @@ int sbi_probe_extension(int extid) }EXPORT_SYMBOL (sbi_probe_extension); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir) +{
arch/riscv/kernel/sbi.c int sbi_probe_extension(int extid) · line 537
Quoted 10 lines
arch/riscv/kernel/sbi.c +10
-0+#if 0 +sbi_ecall (SBI_EXT_DMA ,SBI_DMA_SYNC , start, size, dir, +0 ,0 ,0 ); +#else +/* Just for try, it should be in sbi ecall and will be removed before merged */ + register unsigned long i asm("a0") = start & ~(L1_CACHE_BYTES - 1); + +for (; i <ALIGN (start + size,L1_CACHE_BYTES ); i +=L1_CACHE_BYTES ) + __asm__ __volatile__(".long 0x02b5000b" ); +
Hi, I'm trying to use this patch for my D1 board.
Though the above code will be removed, I notice that the use of the inline assembly is wrong and i (i.e. a0) might not be correctly passed to the assembly code when we are using some other compilers.
It should be __asm__ __volatile__(".long 0x02b5000b" : : "r"(i)).
Thanks,
Wende
Quoted 79 lines
arch/riscv/kernel/sbi.c +5
-0+ __asm__ __volatile__(".long 0x01b0000b" ); +#endif +} +EXPORT_SYMBOL (sbi_dma_sync); +static long __sbi_base_ecall (int fid) {struct sbiret ret;arch/riscv/mm/Makefile +1
-0@@ -13,6 +13,7 @@ obj-y += extable.o obj-$(CONFIG_MMU) += fault.o pageattr.o obj-y += cacheflush.o obj-y += context.o +obj-y += dma-mapping.o ifeq ($(CONFIG_MMU),y) obj-$(CONFIG_SMP) += tlbflush.oarch/riscv/mm/dma-mapping.c new file +53
-0@@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/dma-map-ops.h> +#include <asm/sbi.h> + +void arch_dma_prep_coherent (struct page *page,size_t size) +{ +void *ptr =page_address (page); + +memset (ptr,0 , size); +sbi_dma_sync (page_to_phys (page), size,SBI_DMA_BIDIRECTIONAL ); +} + +void arch_sync_dma_for_device (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +switch (dir) { +case DMA_TO_DEVICE : +case DMA_FROM_DEVICE : +case DMA_BIDIRECTIONAL : +sbi_dma_sync (paddr, size, dir); +break ; +default : +BUG (); + } +} + +void arch_sync_dma_for_cpu (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +switch (dir) { +case DMA_TO_DEVICE : +return ; +case DMA_FROM_DEVICE : +case DMA_BIDIRECTIONAL : +sbi_dma_sync (paddr, size, dir); +break ; +default : +BUG (); + } +} + +pgprot_t phys_mem_access_prot (struct file *file,unsigned long pfn, +unsigned long size,pgprot_t vma_prot) +{ +if (!pfn_valid (pfn)) +return pgprot_noncached (vma_prot); +else if (file->f_flags &O_SYNC ) +return pgprot_writecombine (vma_prot); + +return vma_prot; +} +EXPORT_SYMBOL (phys_mem_access_prot);
Signature · 4 lines
Best wishes! Sincerely, twd2 https://twd2.me
Re: [RFC PATCH v2 07/11] riscv: cmo: Add dma-noncoherency support
Quoted 168 lines · On Sun, Oct 17, 2021 at 5:28 PM twd2 <[email protected]> wrote:
Quoted 151 lines · On 2021/6/6 17:04, [email protected] wrote:
From: Guo Ren <[email protected]>
To support DMA device in a non-coherent interconnect SOC system, we need the below facilities:
- Changing a virtual memory mapping region attributes from cacheable to noncache + strong order which used in DMA descriptors.
- Add noncache + weakorder virtual memory attributes for dma mapping.
- Syncing the cache with memory before DMA start and after DMA end with vendor custom CMO instructions.This patch enables linux kernel generic dma-noncoherency infrastructure and introduces new
sbi_ecallAPI fordma_sync.arch/riscv/include/asm/sbi.h +1
-0@@ -27,6 +27,7 @@ enum sbi_ext_id { + SBI_EXT_DMA = 0xAB150401,Signed-off-by Guo Ren <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Anup Patel <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Drew Fustini <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>--- arch/riscv/Kconfig | 5 ++++ arch/riscv/include/asm/pgtable.h | 26 ++++++++++++++++++++ arch/riscv/include/asm/sbi.h | 15 ++++++++++++ arch/riscv/kernel/sbi.c | 19 ++++++++++++++ arch/riscv/mm/Makefile | 1 + arch/riscv/mm/dma-mapping.c | 53 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+) create mode 100644 arch/riscv/mm/dma-mapping.carch/riscv/Kconfig +5
-0@@ -20,6 +20,10 @@ config RISCV select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_WX + select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE@@ -43,6 +47,7 @@ config RISCV select CLONE_BACKWARDS select CLINT_TIMER if !MMU select COMMON_CLK + select DMA_DIRECT_REMAP select EDAC_SUPPORT select GENERIC_ARCH_TOPOLOGY if SMP select GENERIC_ATOMIC64 if !64BITarch/riscv/include/asm/pgtable.h +26
-0@@ -462,6 +462,32 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,return ptep_test_and_clear_young (vma, address, ptep); } +#define pgprot_noncached pgprot_noncached +static inline pgprot_t pgprot_noncached (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_IO; + +return __pgprot (prot); +} + +#define pgprot_writecombine pgprot_writecombine +static inline pgprot_t pgprot_writecombine (pgprot_t _prot) +{ +unsigned long prot =pgprot_val (_prot); + + prot &= ~_PAGE_DMA_MASK; + prot |= _PAGE_DMA_WC; + +return __pgprot (prot); +} + +#define __HAVE_PHYS_MEM_ACCESS_PROT +extern pgprot_t phys_mem_access_prot (struct file *file,unsigned long pfn, +unsigned long size,pgprot_t vma_prot); +/* * Encode and decode a swap entry * arch/riscv/include/asm/sbi.h +15
-0@@ -27,6 +27,7 @@ enum sbi_ext_id {SBI_EXT_IPI =0x735049 ,SBI_EXT_RFENCE =0x52464E43 ,SBI_EXT_HSM =0x48534D , + SBI_EXT_DMA = 0xAB150401, }; enum sbi_ext_base_fid {@@ -63,6 +64,17 @@ enum sbi_ext_hsm_fid { SBI_EXT_HSM_HART_STATUS, }; +enum sbi_ext_dma_fid { +SBI_DMA_SYNC =0 , +}; + +enum sbi_dma_sync_data_direction { +SBI_DMA_BIDIRECTIONAL =0 , +SBI_DMA_TO_DEVICE =1 , +SBI_DMA_FROM_DEVICE =2 , +SBI_DMA_NONE =3 , +}; +enum sbi_hsm_hart_status {SBI_HSM_HART_STATUS_STARTED =0 ,SBI_HSM_HART_STATUS_STOPPED ,@@ -128,6 +140,9 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,unsigned long size, unsigned long asid);int sbi_probe_extension (int ext); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir);/* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1 (void )arch/riscv/kernel/sbi.c +4
-0@@ -521,6 +521,25 @@ int sbi_probe_extension(int extid) }EXPORT_SYMBOL (sbi_probe_extension); +void sbi_dma_sync (unsigned long start, +unsigned long size, +enum sbi_dma_sync_data_direction dir) +{arch/riscv/kernel/sbi.c int sbi_probe_extension(int extid) · line 537
Quoted 10 lines
arch/riscv/kernel/sbi.c +10
-0+#if 0 +sbi_ecall (SBI_EXT_DMA ,SBI_DMA_SYNC , start, size, dir, +0 ,0 ,0 ); +#else +/* Just for try, it should be in sbi ecall and will be removed before merged */ + register unsigned long i asm("a0") = start & ~(L1_CACHE_BYTES - 1); + +for (; i <ALIGN (start + size,L1_CACHE_BYTES ); i +=L1_CACHE_BYTES ) + __asm__ __volatile__(".long 0x02b5000b" ); +Hi, I'm trying to use this patch for my D1 board.
Quoted 4 lines
Though the above code will be removed, I notice that the use of the inline assembly is wrong and
i(i.e.a0) might not be correctly passed to the assembly code when we are using some other compilers.It should be
__asm__ __volatile__(".long 0x02b5000b" : : "r"(i)).
Yes, I should keep "r"(I).
Thx
Quoted 92 lines
Thanks,
WendeQuoted 69 lines
arch/riscv/kernel/sbi.c +5
-0+ __asm__ __volatile__(".long 0x01b0000b" ); +#endif +} +EXPORT_SYMBOL (sbi_dma_sync); +static long __sbi_base_ecall (int fid) {struct sbiret ret;arch/riscv/mm/Makefile +1
-0@@ -13,6 +13,7 @@ obj-y += extable.o obj-$(CONFIG_MMU) += fault.o pageattr.o obj-y += cacheflush.o obj-y += context.o +obj-y += dma-mapping.o ifeq ($(CONFIG_MMU),y) obj-$(CONFIG_SMP) += tlbflush.oarch/riscv/mm/dma-mapping.c new file +43
-0@@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/dma-map-ops.h> +#include <asm/sbi.h> + +void arch_dma_prep_coherent (struct page *page,size_t size) +{ +void *ptr =page_address (page); + +memset (ptr,0 , size); +sbi_dma_sync (page_to_phys (page), size,SBI_DMA_BIDIRECTIONAL ); +} + +void arch_sync_dma_for_device (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +switch (dir) { +case DMA_TO_DEVICE : +case DMA_FROM_DEVICE : +case DMA_BIDIRECTIONAL : +sbi_dma_sync (paddr, size, dir); +break ; +default : +BUG (); + } +} + +void arch_sync_dma_for_cpu (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +switch (dir) { +case DMA_TO_DEVICE : +return ; +case DMA_FROM_DEVICE : +case DMA_BIDIRECTIONAL : +sbi_dma_sync (paddr, size, dir); +break ; +default : +BUG (); + } +} + +pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,arch/riscv/mm/dma-mapping.c line 53
Quoted 10 lines
arch/riscv/mm/dma-mapping.c new file +10
-0+ unsigned long size, pgprot_t vma_prot) +{ +if (!pfn_valid (pfn)) +return pgprot_noncached (vma_prot); +else if (file->f_flags &O_SYNC ) +return pgprot_writecombine (vma_prot); + +return vma_prot; +} +EXPORT_SYMBOL (phys_mem_access_prot);--
Best wishes!
Sincerely,
twd2
https://twd2.me
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
RFC PATCH v2 8/11 riscv: cmo: Add vendor custom icache sync
In reply to [email protected]From: Guo Ren <[email protected]>
It's a draft version to show you how T-HEAD C9xx work with the icache sync (We use hardware broadcast mechanism, and our icache is VIPT):
- icache.i(v/p)a will broadcast all harts' icache invalidtion
- sync.is will broadcast all harts' pipeline flush and ensure all broadcasts finished.
This patch could improve the performance of OpenJDK on JIT and reduce flush_icache_all in linux.
Epecially:
static inline void set_pte_at(struct mm_struct *mm,
unsigned long addr, pte_t *ptep, pte_t pteval)
{
if (pte_present(pteval) && pte_exec(pteval))
flush_icache_pte(pteval);
set_pte(ptep, pteval);
}Different from sbi_dma_sync, it can't be hidden in SBI and we must set up a framework to hold all vendors' implementations in linux/arch/riscv.
--- arch/riscv/include/asm/cacheflush.h | 48 ++++++++++++++++++++++++++++++++++- arch/riscv/kernel/vdso/flush_icache.S | 33 +++++++++++++++++++----- arch/riscv/mm/cacheflush.c | 3 ++- 3 files changed, 76 insertions(+), 8 deletions(-)
arch/riscv/include/asm/cacheflush.h +47 -1
@@ -22,11 +22,57 @@ static inline void flush_dcache_page(struct page *page) }#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +#define ICACHE_IPA_X5 ".long 0x0382800b" +#define ICACHE_IVA_X5 ".long 0x0302800b" +#define SYNC_IS ".long 0x01b0000b" + +static inline void flush_icache_range (unsigned long start,unsigned long end) +{ + register unsigned long tmp asm("x5") = start & (~(L1_CACHE_BYTES-1)); + +for (; tmp <ALIGN (end,L1_CACHE_BYTES ); tmp +=L1_CACHE_BYTES ) { + __asm__ __volatile__ ( + ICACHE_IVA_X5 + : + : "r" (tmp) + : "memory"); + } + + __asm__ __volatile__(SYNC_IS); + +return ; +} + +static inline void flush_icache_range_phy (unsigned long start,unsigned long end) +{ + register unsigned long tmp asm("x5") = start & (~(L1_CACHE_BYTES-1)); + +for (; tmp <ALIGN (end,L1_CACHE_BYTES ); tmp +=L1_CACHE_BYTES ) { + __asm__ __volatile__ ( + ICACHE_IPA_X5 + : + : "r" (tmp) + : "memory"); + } + + __asm__ __volatile__(SYNC_IS); + + return; +} + +static inline void __flush_icache_page (struct page *page) { +unsigned long start =PFN_PHYS (page_to_pfn (page)); + +flush_icache_range_phy (start, start +PAGE_SIZE ); + +return ; +} +/* * RISC-V doesn't have an instruction to flush parts of the instruction cache, * so instead we just flush the whole thing. */ -#define flush_icache_range (start, end) flush_icache_all() +#define flush_icache_range (start, end) flush_icache_range(start, end)#define flush_icache_user_page (vma, pg, addr, len) \ flush_icache_mm(vma->vm_mm, 0)
arch/riscv/kernel/vdso/flush_icache.S +27 -6
@@ -5,18 +5,39 @@ #include <linux/linkage.h> #include <asm/unistd.h> +#include <asm/cache.h> + +/* + * icache.ipa rs1 + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 11000 rs1 000 00000 0001011 + * + * icache.iva rs1 + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 10000 rs1 000 00000 0001011 + * + * sync.is + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000000 11011 00000 000 00000 0001011 + */ +#define ICACHE_IPA_X5 .long 0x0382800b +#define ICACHE_IVA_X5 .long 0x0302800b +#define SYNC_IS .long 0x01b0000b .text /* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */ ENTRY(__vdso_flush_icache) .cfi_startproc -#ifdef CONFIG_SMP - li a7, __NR_riscv_flush_icache - ecall -#else - fence.i + srli t0, a0, L1_CACHE_SHIFT + slli t0, t0, L1_CACHE_SHIFT + addi a1, a1, (L1_CACHE_BYTES - 1) + srli a1, a1, L1_CACHE_SHIFT + slli a1, a1, L1_CACHE_SHIFT +1: ICACHE_IVA_X5 + addi t0, t0, L1_CACHE_BYTES + bne t0, a1, 1b + SYNC_IS li a0, 0 -#endif ret .cfi_endproc ENDPROC(__vdso_flush_icache)
arch/riscv/mm/cacheflush.c +2 -1
@@ -3,6 +3,7 @@* Copyright (C) 2017 SiFive */ +#include <linux/pfn.h> #include <asm/cacheflush.h> #ifdef CONFIG_SMP
@@ -84,6 +85,6 @@ void flush_icache_pte(pte_t pte)struct page *page =pte_page (pte);if (!test_and_set_bit (PG_dcache_clean, &page->flags)) - flush_icache_all(); + __flush_icache_page(page); }#endif /* CONFIG_MMU */
Signature · 1 line
2.7.4
RFC PATCH v2 9/11 riscv: soc: Initial DTS for Allwinner D1 NeZha board
In reply to [email protected]From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
arch/riscv/boot/dts/Makefile +1 -0
@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
arch/riscv/boot/dts/allwinner/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +29 -0
@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit"; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + }; + + soc { + }; +}; + +&serial0 { + status = "okay"; +};
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +84 -0
84 lines not on this page · raw message
Signature · 1 line
2.7.4
Jernej Škrabec
maintainerRe: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Hi!
I didn't go through all details. After you fix all comments below, you should run "make dtbs_check" and fix all reported warnings too.
Dne nedelja, 06. junij 2021 ob 11:04:07 CEST je [email protected] napisal(a):
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts
Quoted 52 lines
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))(quoted diff) +0
-0b/arch/riscv/boot/dts/allwinner/Makefile new file mode 100644 index 00000000..4adbf4b
arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsnew file mode 100644
index 00000000..cd9f7c9arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +0
-0
Board DT names are comprised of soc name and board name, in this case it would be "sun20i-d1-nezha-kit.dts"
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 1
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +1
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
Usually copyrights are added below spdx id.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 9
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +8
-0+ +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>;
This should be part of SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 11
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +2
-0+ model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit";
Board specific compatible string should be followed with SoC compatible, in this case "allwinner,sun20i-d1". You should document it too.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + chosen { + bootargs = "console=ttyS0,115200";
Above line doesn't belong here. If anything, it should be added dynamically by bootloader.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 21
Quoted 7 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +7
-0+ stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + };
Ditto for whole memory node.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 24
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + soc { + };
There is no point having empty nodes.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +5
-0+}; + +&serial0 { + status = "okay"; +};(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1.dtsinew file mode 100644 index 00000000..11cd938arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +0
-0
Current naming approach for Allwinner SoC level DTSI is "sun20i-d1.dtsi".
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 7
Quoted 9 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +7
-0@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>;
Since all peripherals and memory are below 4 GiB, why have 64-bit addresses and sizes? It just clutters DT.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 9
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +2
-0+ model = "Allwinner D1 Soc"; + compatible = "allwinner,d1-nezha-kit";
Compatible and model don't belong to SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +3
-0+ + chosen { + };
Remove empty node.
Quoted 51 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +51
-0+ + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <2400000>; + cpu@0 { + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcv"; + mmu-type = "riscv,sv39"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + }; + + clint: clint@14000000 { + compatible = "riscv,clint0"; + interrupts-extended = < + &cpu0_intc 3 &cpu0_intc 7 + >; + reg = <0x0 0x14000000 0x0 0x04000000>; + clint,has-no-64bit-mmio; + }; + + plic: interrupt-controller@10000000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = < + &cpu0_intc 0xffffffff &cpu0_intc 9 + >; + reg = <0x0 0x10000000 0x0 0x04000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <200>;
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 73
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +10
-0+ }; + + dummy_apb: apb-clock { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "dummy_apb"; + #clock-cells = <0>; + }; + + serial0: serial@2500000 {
This should be uart0 and board should have alias for it. Check ARM based Allwinner DTs.
Best regards,
Jernej
Quoted 11 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +11
-0+ compatible = "snps,dw-apb-uart"; + reg = <0x0 0x02500000 0x0 0x400>; + reg-io-width = <4>; + reg-shift = <2>; + interrupt-parent = <&plic>; + interrupts = <18>; + clocks = <&dummy_apb>; + status = "disabled"; + }; + }; +};
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Quoted 63 lines · Jernej Škrabec
Hi!
I didn't go through all details. After you fix all comments below, you should run "make
dtbs_check" and fix all reported warnings too.Dne nedelja, 06. junij 2021 ob 11:04:07 CEST je [email protected] napisal(a):
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts
Quoted 52 lines
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))(quoted diff) +0
-0b/arch/riscv/boot/dts/allwinner/Makefile new file mode 100644 index 00000000..4adbf4b
arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsnew file mode 100644
index 00000000..cd9f7c9arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +0
-0Board DT names are comprised of soc name and board name, in this case it would be "
sun20i-d1-nezha-kit.dts"
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 1
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +1
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)Usually copyrights are added below spdx id.
No certain copyrights, maybe let allwinner added later.
Quoted 12 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 9
Quoted 9 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +8
-0+ +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>;This should be part of SoC level DTSI.
Quoted 5 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 11
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +2
-0+ model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit";Board specific compatible string should be followed with SoC compatible, in this case "allwinner,sun20i-d1". You should document it too.
Okay
Quoted 7 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + chosen { + bootargs = "console=ttyS0,115200";Above line doesn't belong here. If anything, it should be added dynamically by bootloader.
Okay
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 21
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +7
-0+ stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + };Ditto for whole memory node.
Okay remove it and let u-boot append.
Quoted 6 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 24
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + soc { + };There is no point having empty nodes.
Okay.
Quoted 30 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 11 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +5
-0+}; + +&serial0 { + status = "okay"; +};(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1.dtsinew file mode 100644 index 00000000..11cd938arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +0
-0Current naming approach for Allwinner SoC level DTSI is "
sun20i-d1.dtsi".arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 7
Quoted 9 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +7
-0@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>;Since all peripherals and memory are below 4 GiB, why have 64-bit addresses and sizes? It just clutters DT.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 9
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +2
-0+ model = "Allwinner D1 Soc"; + compatible = "allwinner,d1-nezha-kit";
Quoted 7 lines
Compatible and model don't belong to SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +3
-0+ + chosen { + };Remove empty node.
Okay.
Quoted 57 lines
Quoted 57 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +56
-0+ + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <2400000>; + cpu@0 { + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcv"; + mmu-type = "riscv,sv39"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + }; + + clint: clint@14000000 { + compatible = "riscv,clint0"; + interrupts-extended = < + &cpu0_intc 3 &cpu0_intc 7 + >; + reg = <0x0 0x14000000 0x0 0x04000000>; + clint,has-no-64bit-mmio; + }; + + plic: interrupt-controller@10000000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = < + &cpu0_intc 0xffffffff &cpu0_intc 9 + >; + reg = <0x0 0x10000000 0x0 0x04000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <200>; + }; + + dummy_apb: apb-clock { + compatible = "fixed-clock"; + clock-frequency = <24000000>;
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 73
Quoted 5 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +5
-0+ clock-output-names = "dummy_apb"; + #clock-cells = <0>; + }; + + serial0: serial@2500000 {This should be uart0 and board should have alias for it. Check ARM based Allwinner DTs.
Okay, use the uart0 alias.
Quoted 19 lines
Best regards,
JernejQuoted 11 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +11
-0+ compatible = "snps,dw-apb-uart"; + reg = <0x0 0x02500000 0x0 0x400>; + reg-io-width = <4>; + reg-shift = <2>; + interrupt-parent = <&plic>; + interrupts = <18>; + clocks = <&dummy_apb>; + status = "disabled"; + }; + }; +};
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
In reply to Jernej ŠkrabecQuoted 85 lines · Jernej Škrabec
Hi!
I didn't go through all details. After you fix all comments below, you should run "make
dtbs_check" and fix all reported warnings too.Dne nedelja, 06. junij 2021 ob 11:04:07 CEST je [email protected] napisal(a):
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts
Quoted 52 lines
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))(quoted diff) +0
-0b/arch/riscv/boot/dts/allwinner/Makefile new file mode 100644 index 00000000..4adbf4b
arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsnew file mode 100644
index 00000000..cd9f7c9arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +0
-0Board DT names are comprised of soc name and board name, in this case it would be "
sun20i-d1-nezha-kit.dts"arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 1
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +1
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)Usually copyrights are added below spdx id.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 9
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +8
-0+ +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>;This should be part of SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 11
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +2
-0+ model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit";Board specific compatible string should be followed with SoC compatible, in this case "allwinner,sun20i-d1". You should document it too.
Quoted 6 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + chosen { + bootargs = "console=ttyS0,115200";Above line doesn't belong here. If anything, it should be added dynamically by bootloader.
After discussion, we still want to keep a default value here. Sometimes we could boot with jtag and parse dtb is hard for gdbinit script.
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 21
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +7
-0+ stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + };Ditto for whole memory node.
Ditto
Quoted 127 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 24
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + soc { + };There is no point having empty nodes.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +5
-0+}; + +&serial0 { + status = "okay"; +};(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1.dtsinew file mode 100644 index 00000000..11cd938arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +0
-0Current naming approach for Allwinner SoC level DTSI is "
sun20i-d1.dtsi".arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 7
Quoted 9 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +7
-0@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>;Since all peripherals and memory are below 4 GiB, why have 64-bit addresses and sizes? It just clutters DT.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 9
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +2
-0+ model = "Allwinner D1 Soc"; + compatible = "allwinner,d1-nezha-kit";Compatible and model don't belong to SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +3
-0+ + chosen { + };Remove empty node.
Quoted 51 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +51
-0+ + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <2400000>; + cpu@0 { + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcv"; + mmu-type = "riscv,sv39"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + }; + + clint: clint@14000000 { + compatible = "riscv,clint0"; + interrupts-extended = < + &cpu0_intc 3 &cpu0_intc 7 + >; + reg = <0x0 0x14000000 0x0 0x04000000>; + clint,has-no-64bit-mmio; + }; + + plic: interrupt-controller@10000000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = < + &cpu0_intc 0xffffffff &cpu0_intc 9 + >; + reg = <0x0 0x10000000 0x0 0x04000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <200>;arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 73
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +10
-0+ }; + + dummy_apb: apb-clock { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "dummy_apb"; + #clock-cells = <0>; + }; + + serial0: serial@2500000 {This should be uart0 and board should have alias for it. Check ARM based Allwinner DTs.
Best regards,
JernejQuoted 11 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +11
-0+ compatible = "snps,dw-apb-uart"; + reg = <0x0 0x02500000 0x0 0x400>; + reg-io-width = <4>; + reg-shift = <2>; + interrupt-parent = <&plic>; + interrupts = <18>; + clocks = <&dummy_apb>; + status = "disabled"; + }; + }; +};
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Quoted 106 lines · Guo Ren
Quoted 85 lines · Jernej Škrabec
Hi!
I didn't go through all details. After you fix all comments below, you should run "make
dtbs_check" and fix all reported warnings too.Dne nedelja, 06. junij 2021 ob 11:04:07 CEST je [email protected] napisal(a):
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts
Quoted 52 lines
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))(quoted diff) +0
-0b/arch/riscv/boot/dts/allwinner/Makefile new file mode 100644 index 00000000..4adbf4b
arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsnew file mode 100644
index 00000000..cd9f7c9arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +0
-0Board DT names are comprised of soc name and board name, in this case it would be "
sun20i-d1-nezha-kit.dts"arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 1
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +1
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)Usually copyrights are added below spdx id.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 9
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +8
-0+ +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>;This should be part of SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 11
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +2
-0+ model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit";Board specific compatible string should be followed with SoC compatible, in this case "allwinner,sun20i-d1". You should document it too.
Quoted 6 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + chosen { + bootargs = "console=ttyS0,115200";Above line doesn't belong here. If anything, it should be added dynamically by bootloader.
After discussion, we still want to keep a default value here. Sometimes we could boot with jtag and parse dtb is hard for gdbinit script.
Quoted 9 lines
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +7
-0+ stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + };
Quoted 3 lines
Quoted 1 line
Ditto for whole memory node.
Ditto
The thing is that there's never a good value for a default. Let's take the memory node here: what would be a good default? If we want to make it work everywhere it's going to be the lowest amount of memory available on the D1 boards. It's going to be hard to maintain and very likely to be overlooked, resulting in broken boards anyway.
If someone is savvy enough to use JTAG, it's not really difficult to modify the DT for their board when they need it.
Maxime
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Thx for the clarification.
Quoted 112 lines · Maxime Ripard
Quoted 106 lines · Guo Ren
Quoted 85 lines · Jernej Škrabec
Hi!
I didn't go through all details. After you fix all comments below, you should run "make
dtbs_check" and fix all reported warnings too.Dne nedelja, 06. junij 2021 ob 11:04:07 CEST je [email protected] napisal(a):
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts
Quoted 52 lines
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))(quoted diff) +0
-0b/arch/riscv/boot/dts/allwinner/Makefile new file mode 100644 index 00000000..4adbf4b
arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtb(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsnew file mode 100644
index 00000000..cd9f7c9arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +0
-0Board DT names are comprised of soc name and board name, in this case it would be "
sun20i-d1-nezha-kit.dts"arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 1
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +1
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)Usually copyrights are added below spdx id.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 9
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +8
-0+ +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>;This should be part of SoC level DTSI.
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 11
Quoted 2 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +2
-0+ model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit";Board specific compatible string should be followed with SoC compatible, in this case "allwinner,sun20i-d1". You should document it too.
Quoted 6 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 3 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +3
-0+ + chosen { + bootargs = "console=ttyS0,115200";Above line doesn't belong here. If anything, it should be added dynamically by bootloader.
After discussion, we still want to keep a default value here. Sometimes we could boot with jtag and parse dtb is hard for gdbinit script.
Quoted 9 lines
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +7
-0+ stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + };Quoted 3 lines
Quoted 1 line
Ditto for whole memory node.
Ditto
Quoted 8 lines
The thing is that there's never a good value for a default. Let's take the memory node here: what would be a good default? If we want to make it work everywhere it's going to be the lowest amount of memory available on the D1 boards. It's going to be hard to maintain and very likely to be overlooked, resulting in broken boards anyway.
If someone is savvy enough to use JTAG, it's not really difficult to modify the DT for their board when they need it.
okay, I see. I'll follow the rule in the next version of the patchset.
Quoted 2 lines
Maxime
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
In reply to [email protected]Hi,
Thanks for the patches
Quoted 17 lines · On Sun, Jun 06, 2021 at 09:04:07AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>
Quoted 5 lines
--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++
Can you add the riscv folder to our MAINTAINERS entry as well?
Quoted 10 lines
4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiarch/riscv/boot/dts/Makefile +0
-0
arch/riscv/boot/dts/Makefile line 5
Quoted 4 lines
arch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinner
I assume they should be ordered alphabetically?
Quoted 82 lines
arch/riscv/boot/dts/Makefile +0
-0obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtbarch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +29
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit"; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + }; + + soc { + }; +}; + +&serial0 { + status = "okay"; +};arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +32
-0@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Allwinner D1 Soc"; + compatible = "allwinner,d1-nezha-kit"; + + chosen { + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <2400000>; + cpu@0 { + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcv"; + mmu-type = "riscv,sv39"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; +
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 42
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +10
-0+ soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + };
This compatible is not documented anywhere?
Maxime
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Quoted 29 lines · Maxime Ripard
Hi,
Thanks for the patches
Quoted 17 lines · On Sun, Jun 06, 2021 at 09:04:07AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add initial DTS for Allwinner D1 NeZha board having only essential devices (uart, dummy, clock, reset, clint, plic, etc).
Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Quoted 5 lines
--- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 ++++++++ arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 84 ++++++++++++++++++++++
Quoted 1 line
Can you add the riscv folder to our
MAINTAINERSentry as well?
Yes
Quoted 6 lines
Quoted 6 lines
4 files changed, 116 insertions(+) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi
Quoted 11 lines
arch/riscv/boot/dts/Makefile line 5
Quoted 9 lines
arch/riscv/boot/dts/Makefile +1
-0@@ -2,5 +2,6 @@ subdir-y += sifive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip +subdir-y += allwinnerI assume they should be ordered alphabetically?
Thx for pointing it out.
Quoted 87 lines
Quoted 87 lines
arch/riscv/boot/dts/Makefile +0
-0obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))arch/riscv/boot/dts/allwinner/Makefile new file +2
-0@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_SUNXI) += allwinner-d1-nezha-kit.dtbarch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts new file +29
-0@@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include "allwinner-d1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Allwinner D1 NeZha Kit"; + compatible = "allwinner,d1-nezha-kit"; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &serial0; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + }; + + soc { + }; +}; + +&serial0 { + status = "okay"; +};arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +36
-0@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Allwinner D1 Soc"; + compatible = "allwinner,d1-nezha-kit"; + + chosen { + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <2400000>; + cpu@0 { + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcv"; + mmu-type = "riscv,sv39"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus";
Quoted 8 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 42
Quoted 6 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +6
-0+ ranges; + + reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + };This compatible is not documented anywhere?
It used by opensbi (riscv runtime firmware), not in Linux. But I think we should keep it.
Quoted 2 lines
Maxime
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Quoted 10 lines · Guo Ren
Quoted 6 lines · Maxime Ripard
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 42
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +4
-0+ reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + };This compatible is not documented anywhere?
It used by opensbi (riscv runtime firmware), not in Linux. But I think we should keep it.
This should have a documentation still.
Maxime
Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Quoted 8 lines · Maxime Ripard
Quoted 6 lines · Guo Ren
Quoted 5 lines · Maxime Ripard
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +4
-0+ reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + };
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
This compatible is not documented anywhere?
It used by opensbi (riscv runtime firmware), not in Linux. But I think we should keep it.
This should have a documentation still.
Could we detail the above in [1]?
1: https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
Quoted 2 lines
Maxime
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Jernej Škrabec
maintainerRe: Re: [RFC PATCH v2 09/11] riscv: soc: Initial DTS for Allwinner D1 NeZha board
Dne ponedeljek, 14. junij 2021 ob 18:28:28 CEST je Guo Ren napisal(a):
Quoted 9 lines · Maxime Ripard
Quoted 8 lines · Guo Ren
Quoted 6 lines · Maxime Ripard
Quoted 5 lines
Quoted 4 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi new file +4
-0+ reset: reset-sample { + compatible = "thead,reset-sample"; + plic-delegate = <0x0 0x101ffffc>; + };
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
This compatible is not documented anywhere?
It used by opensbi (riscv runtime firmware), not in Linux. But I think we should keep it.
This should have a documentation still.
Could we detail the above in [1]?
All DT nodes must be documented in Documentation/devicetree/bindings folder in yaml format, so DTs can be machine verified.
Best regards,
Jernej
Quoted 15 lines
1: https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
Quoted 2 lines
Maxime
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
RFC PATCH v2 10/11 riscv: soc: Add Allwinner SoC kconfig option
In reply to [email protected]From: Guo Ren <[email protected]>
Add Allwinner kconfig option which selects SoC specific and common drivers that is required for this SoC.
Allwinner D1 uses custom PTE attributes to solve non-coherency SOC interconnect issues for dma synchronization, so we set the default value when SOC_SUNXI selected.
--- arch/riscv/Kconfig.socs | 12 ++++++++++++ arch/riscv/configs/defconfig | 1 + 2 files changed, 13 insertions(+)
arch/riscv/Kconfig.socs +12 -0
@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif +config SOC_SUNXI + bool "Allwinner SoCs" + depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. + endmenu
arch/riscv/configs/defconfig +1 -0
@@ -15,6 +15,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_BPF_SYSCALL=y CONFIG_SOC_SIFIVE=y +CONFIG_SOC_SUNXI=y CONFIG_SOC_VIRT=y CONFIG_SOC_MICROCHIP_POLARFIRE=y CONFIG_SMP=y
Signature · 1 line
2.7.4
Re: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
Hi,
Quoted 36 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add Allwinner kconfig option which selects SoC specific and common drivers that is required for this SoC.
Allwinner D1 uses custom PTE attributes to solve non-coherency SOC interconnect issues for dma synchronization, so we set the default value when
SOC_SUNXIselected.Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/Kconfig.socs | 12 ++++++++++++ arch/riscv/configs/defconfig | 1 + 2 files changed, 13 insertions(+)arch/riscv/Kconfig.socs +2
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif +config SOC_SUNXI + bool "Allwinner SoCs"
arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 10 lines
arch/riscv/Kconfig.socs +10
-0+ depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +
We probably don't want to select DWMAC, STMMAC_ETH and the 8250 options, looks good otherwise.
Maxime
Arnd Bergmann
maintainerRe: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
Quoted 10 lines · Maxime Ripard
Quoted 8 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
arch/riscv/Kconfig.socs +0
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif
Quoted 15 lines
arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 12 lines
arch/riscv/Kconfig.socs +12
-0+config SOC_SUNXI + bool "Allwinner SoCs" + depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +We probably don't want to select DWMAC,
STMMAC_ETHand the 8250 options, looks good otherwise.
Correct: those subsystems may be completely disabled, which would lead to a build failure, and a platform should not force-enable drivers or subsystems unless
those are build time dependencies.
Arnd
Re: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
Quoted 28 lines · Arnd Bergmann
Quoted 10 lines · Maxime Ripard
Quoted 8 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
arch/riscv/Kconfig.socs +0
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endifQuoted 15 lines
arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 12 lines
arch/riscv/Kconfig.socs +12
-0+config SOC_SUNXI + bool "Allwinner SoCs" + depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +We probably don't want to select DWMAC,
STMMAC_ETHand the 8250 options, looks good otherwise.
Quoted 6 lines
Correct: those subsystems may be completely disabled, which would lead to a build failure, and a platform should not force-enable drivers or subsystems unless
those are build time dependencies.Arnd
I see, thx. how about just leave. I think the user would make mistakes and waste time here.
select SERIAL_8250_DW if SERIAL_8250
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
In reply to Maxime RipardQuoted 54 lines · Maxime Ripard
Hi,
Quoted 36 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add Allwinner kconfig option which selects SoC specific and common drivers that is required for this SoC.
Allwinner D1 uses custom PTE attributes to solve non-coherency SOC interconnect issues for dma synchronization, so we set the default value when
SOC_SUNXIselected.Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/Kconfig.socs | 12 ++++++++++++ arch/riscv/configs/defconfig | 1 + 2 files changed, 13 insertions(+)arch/riscv/Kconfig.socs +2
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif +config SOC_SUNXI + bool "Allwinner SoCs"arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 10 lines
arch/riscv/Kconfig.socs +10
-0+ depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +We probably don't want to select DWMAC,
STMMAC_ETHand the 8250 options, looks good otherwise.
Quoted 1 line
Maxime
Remove DWMAC, STMMAC_ETH is okay.
But I think we still need:
select SERIAL_8250_DW if SERIAL_8250
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
Quoted 55 lines · Guo Ren
Quoted 54 lines · Maxime Ripard
Hi,
Quoted 36 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add Allwinner kconfig option which selects SoC specific and common drivers that is required for this SoC.
Allwinner D1 uses custom PTE attributes to solve non-coherency SOC interconnect issues for dma synchronization, so we set the default value when
SOC_SUNXIselected.Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/Kconfig.socs | 12 ++++++++++++ arch/riscv/configs/defconfig | 1 + 2 files changed, 13 insertions(+)arch/riscv/Kconfig.socs +2
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif +config SOC_SUNXI + bool "Allwinner SoCs"arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 10 lines
arch/riscv/Kconfig.socs +10
-0+ depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +We probably don't want to select DWMAC,
STMMAC_ETHand the 8250 options, looks good otherwise.
Quoted 5 lines
Quoted 1 line
Maxime
Remove DWMAC,
STMMAC_ETHis okay.But I think we still need:
selectSERIAL_8250_DWifSERIAL_8250
Well, even the UART is optional. Just enable them in the defconfig
Maxime
Re: [RFC PATCH v2 10/11] riscv: soc: Add Allwinner SoC kconfig option
Quoted 57 lines · Maxime Ripard
Quoted 55 lines · Guo Ren
Quoted 54 lines · Maxime Ripard
Hi,
Quoted 36 lines · On Sun, Jun 06, 2021 at 09:04:08AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
Add Allwinner kconfig option which selects SoC specific and common drivers that is required for this SoC.
Allwinner D1 uses custom PTE attributes to solve non-coherency SOC interconnect issues for dma synchronization, so we set the default value when
SOC_SUNXIselected.Signed-off-by Guo Ren <[email protected]>Co-Developed-by Liu Shaohua <[email protected]>Signed-off-by Liu Shaohua <[email protected]>Cc Anup Patel <[email protected]>Cc Atish Patra <[email protected]>Cc Christoph Hellwig <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Drew Fustini <[email protected]>Cc Maxime Ripard <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>--- arch/riscv/Kconfig.socs | 12 ++++++++++++ arch/riscv/configs/defconfig | 1 + 2 files changed, 13 insertions(+)arch/riscv/Kconfig.socs +2
-0@@ -69,4 +69,16 @@ config SOC_CANAAN_K210_DTB_SOURCE endif +config SOC_SUNXI + bool "Allwinner SoCs"arch/riscv/Kconfig.socs config SOC_CANAAN_K210_DTB_SOURCE · line 83
Quoted 10 lines
arch/riscv/Kconfig.socs +10
-0+ depends on MMU + select DWMAC_GENERIC + select SERIAL_8250 + select SERIAL_8250_CONSOLE + select SERIAL_8250_DW + select SIFIVE_PLIC + select STMMAC_ETH + help + This enables support for Allwinner SoC platforms like the D1. +We probably don't want to select DWMAC,
STMMAC_ETHand the 8250 options, looks good otherwise.
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Maxime
Remove DWMAC,
STMMAC_ETHis okay.But I think we still need:
selectSERIAL_8250_DWifSERIAL_8250Well, even the UART is optional. Just enable them in the defconfig
Okay
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
RFC PATCH v2 11/11 riscv: soc: Allwinner D1 GMAC driver only for temp use
In reply to [email protected]From: liush <[email protected]>
This is a temporary driver, only guaranteed to work on allwinner D1. In order to ensure the developer's demand for network usage.
It only could work at 1Gps mode.
The correct gmac driver should follow (I guess)drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
If anyone is familiar with it and can help porting, I would be very grateful.
--- .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 2 +- arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 16 + drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- 10 files changed, 3232 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1 -1
@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/init root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23"; stdout-path = &serial0; };
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +16 -0
@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030 0x00 0x04>; + interrupts-extended = <&plic 0x3e 0x04>; + interrupt-names = "gmacirq"; + device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + }; }; };
drivers/net/ethernet/Kconfig +1 -0
@@ -18,6 +18,7 @@ config MDIO config SUNGEM_PHY tristate +source "drivers/net/ethernet/allwinnertmp/Kconfig" source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/actions/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig"
drivers/net/ethernet/Makefile +1 -0
@@ -3,6 +3,7 @@ # Makefile for the Linux network Ethernet device drivers. # +obj-y += allwinnertmp/ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ACTIONS) += actions/
drivers/net/ethernet/allwinnertmp/Kconfig new file +17 -0
@@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Allwinner device configuration +# + +config SUNXI_GMAC + tristate "Allwinner GMAC support" + default y + depends on OF + select CRC32 + select MII + select PHYLIB + help + Support for Allwinner Gigabit ethernet driver. + + To compile this driver as a module, choose M here. The module + will be called sunxi-gmac.
drivers/net/ethernet/allwinnertmp/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Allwinner device drivers. +# + +obj-$(CONFIG_SUNXI_GMAC) += sunxi_gmac.o +sunxi_gmac-objs := sunxi-gmac.o sunxi-gmac-ops.o
drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c new file +690 -0
690 lines not on this page · raw message
drivers/net/ethernet/allwinnertmp/sunxi-gmac.c new file +2240 -0
2,240 lines not on this page · raw message
drivers/net/ethernet/allwinnertmp/sunxi-gmac.h new file +258 -0
3 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.7.4
Part of the diff is not shown here. View the raw message.
Re: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
On Sun, 6 Jun 2021 09:04:09 +0000
[email protected] wrote:
Hi,
Quoted 4 lines
From: liush <[email protected]>
This is a temporary driver, only guaranteed to work on allwinner D1. In order to ensure the developer's demand for network usage.
That looks like some Allwinner BSP driver, please don't endorse code of this quality (just look at all that commented code and the attempt for compile-time configuration).
Quoted 7 lines
It only could work at 1Gps mode.
The correct gmac driver should follow (I guess)
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.cIf anyone is familiar with it and can help porting, I would be very grateful.
Have you tried compiling and using that driver? Ideally it should just work, Linux drivers are meant to be portable, by design. And the driver is already enabled by COMPILE_TEST.
But I guess you need some extra care to make the non-coherent DMA work? I haven't looked in detail, but are those new CMOs hooked into the generic DMA framework?
Cheers,
Andre
Quoted 3,350 lines
Signed-off-by Liu Shaohua <[email protected]>Tested-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc Maxime Ripard <[email protected]>Cc Corentin Labbe <[email protected]>Cc Samuel Holland <[email protected]>Cc Icenowy Zheng <[email protected]>Cc LABBE Corentin <[email protected]>Cc Michael Walle <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Signed-off-by Guo Ren <[email protected]>--- .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 2 +- arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 16 + drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- 10 files changed, 3232 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.harch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/init root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23"; stdout-path = &serial0; };arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +16
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030 0x00 0x04>; + interrupts-extended = <&plic 0x3e 0x04>; + interrupt-names = "gmacirq"; + device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + }; }; };drivers/net/ethernet/Kconfig +1
-0@@ -18,6 +18,7 @@ config MDIO config SUNGEM_PHY tristate +source "drivers/net/ethernet/allwinnertmp/Kconfig" source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/actions/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig"drivers/net/ethernet/Makefile +1
-0@@ -3,6 +3,7 @@ # Makefile for the Linux network Ethernet device drivers. # +obj-y += allwinnertmp/ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ACTIONS) += actions/drivers/net/ethernet/allwinnertmp/Kconfig new file +17
-0@@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Allwinner device configuration +# + +config SUNXI_GMAC + tristate "Allwinner GMAC support" + default y + depends on OF + select CRC32 + select MII + select PHYLIB + help + Support for Allwinner Gigabit ethernet driver. + + To compile this driver as a module, choose M here. The module + will be called sunxi-gmac.drivers/net/ethernet/allwinnertmp/Makefile new file +7
-0@@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Allwinner device drivers. +# + +obj-$(CONFIG_SUNXI_GMAC) += sunxi_gmac.o +sunxi_gmac-objs := sunxi-gmac.o sunxi-gmac-ops.odrivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c new file +690
-0@@ -0,0 +1,690 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c +* +* Copyright © 2016-2018, fuzhaoke +* Author: fuzhaoke <[email protected]> +* +* This file is provided under a dual BSD/GPL license. When using or +* redistributing this file, you may do so under either license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#include <linux/kernel.h> +#include <linux/ctype.h> +#include <linux/printk.h> +#include <linux/io.h> +#include "sunxi-gmac.h" + +/****************************************************************************** +* sun8iw6 operations +*****************************************************************************/ +#define GETH_BASIC_CTL0 0x00 +#define GETH_BASIC_CTL1 0x04 +#define GETH_INT_STA 0x08 +#define GETH_INT_EN 0x0C +#define GETH_TX_CTL0 0x10 +#define GETH_TX_CTL1 0x14 +#define GETH_TX_FLOW_CTL 0x1C +#define GETH_TX_DESC_LIST 0x20 +#define GETH_RX_CTL0 0x24 +#define GETH_RX_CTL1 0x28 +#define GETH_RX_DESC_LIST 0x34 +#define GETH_RX_FRM_FLT 0x38 +#define GETH_RX_HASH0 0x40 +#define GETH_RX_HASH1 0x44 +#define GETH_MDIO_ADDR 0x48 +#define GETH_MDIO_DATA 0x4C +#define GETH_ADDR_HI (reg) (0x50 + ((reg) << 3)) +#define GETH_ADDR_LO (reg) (0x54 + ((reg) << 3)) +#define GETH_TX_DMA_STA 0xB0 +#define GETH_TX_CUR_DESC 0xB4 +#define GETH_TX_CUR_BUF 0xB8 +#define GETH_RX_DMA_STA 0xC0 +#define GETH_RX_CUR_DESC 0xC4 +#define GETH_RX_CUR_BUF 0xC8 +#define GETH_RGMII_STA 0xD0 + +#define RGMII_IRQ 0x00000001 + +#define CTL0_LM 0x02 +#define CTL0_DM 0x01 +#define CTL0_SPEED 0x04 + +#define BURST_LEN 0x3F000000 +#define RX_TX_PRI 0x02 +#define SOFT_RST 0x01 + +#define TX_FLUSH 0x01 +#define TX_MD 0x02 +#define TX_NEXT_FRM 0x04 +#define TX_TH 0x0700 + +#define RX_FLUSH 0x01 +#define RX_MD 0x02 +#define RX_RUNT_FRM 0x04 +#define RX_ERR_FRM 0x08 +#define RX_TH 0x0030 + +#define TX_INT 0x00001 +#define TX_STOP_INT 0x00002 +#define TX_UA_INT 0x00004 +#define TX_TOUT_INT 0x00008 +#define TX_UNF_INT 0x00010 +#define TX_EARLY_INT 0x00020 +#define RX_INT 0x00100 +#define RX_UA_INT 0x00200 +#define RX_STOP_INT 0x00400 +#define RX_TOUT_INT 0x00800 +#define RX_OVF_INT 0x01000 +#define RX_EARLY_INT 0x02000 +#define LINK_STA_INT 0x10000 + +#define DISCARD_FRAME -1 +#define GOOD_FRAME 0 +#define CSUM_NONE 2 +#define LLC_SNAP 4 + +#define SF_DMA_MODE 1 + +/* Flow Control defines */ +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + +#define HASH_TABLE_SIZE 64 +#define PAUSE_TIME 0x200 +#define GMAC_MAX_UNICAST_ADDRESSES 8 + +/* PHY address */ +#define PHY_ADDR 0x01 +#define PHY_DM 0x0010 +#define PHY_AUTO_NEG 0x0020 +#define PHY_POWERDOWN 0x0080 +#define PHY_NEG_EN 0x1000 + +#define MII_BUSY 0x00000001 +#define MII_WRITE 0x00000002 +#define MII_PHY_MASK 0x0000FFC0 +#define MII_CR_MASK 0x0000001C +#define MII_CLK 0x00000008 +/* bits 4 3 2 | AHB1 Clock | MDC Clock +* ------------------------------------------------------- +* 0 0 0 | 60 ~ 100 MHz | div-42 +* 0 0 1 | 100 ~ 150 MHz | div-62 +* 0 1 0 | 20 ~ 35 MHz | div-16 +* 0 1 1 | 35 ~ 60 MHz | div-26 +* 1 0 0 | 150 ~ 250 MHz | div-102 +* 1 0 1 | 250 ~ 300 MHz | div-124 +* 1 1 x | Reserved | +*/ + +enum csum_insertion { + cic_dis =0 ,/* Checksum Insertion Control */ + cic_ip =1 ,/* Only IP header */ + cic_no_pse =2 ,/* IP header but not pseudoheader */ + cic_full =3 ,/* IP header and pseudoheader */ +}; + +struct gethdev { +void *iobase; +unsigned int ver; +unsigned int mdc_div; +}; + +static struct gethdev hwdev; + +/*************************************************************************** +* External interface +**************************************************************************/ +/* Set a ring desc buffer */ +void desc_init_chain (struct dma_desc *desc,unsigned long addr,unsigned int size) +{ +/* In chained mode the desc3 points to the next element in the ring. +* The latest element has to point to the head. +*/ +int i; +struct dma_desc *p = desc; +unsigned long dma_phy = addr; + +for (i =0 ; i < (size -1 ); i++) { + dma_phy +=sizeof (struct dma_desc ); + p->desc3 = (unsigned int )dma_phy; +/* Chain mode */ + p->desc1.all |= (1 <<24 ); + p++; + } + p->desc1.all |= (1 <<24 ); + p->desc3 = (unsigned int )addr; +} + +int sunxi_mdio_read (void *iobase,int phyaddr,int phyreg) +{ +unsigned int value =0 ; + +/* Mask the MDC_DIV_RATIO */ + value |= ((hwdev.mdc_div &0x07 ) <<20 ); + value |= (((phyaddr <<12 ) & (0x0001F000 )) | + ((phyreg <<4 ) & (0x000007F0 )) | +MII_BUSY ); + +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +writel (value, iobase +GETH_MDIO_ADDR ); +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +return (int )readl (iobase +GETH_MDIO_DATA ); +} + +int sunxi_mdio_write (void *iobase,int phyaddr,int phyreg,unsigned short data) +{ +unsigned int value; + + value = ((0x07 <<20 ) &readl (iobase +GETH_MDIO_ADDR )) | + (hwdev.mdc_div <<20 ); + value |= (((phyaddr <<12 ) & (0x0001F000 )) | + ((phyreg <<4 ) & (0x000007F0 ))) | +MII_WRITE |MII_BUSY ; + +/* Wait until any existing MII operation is complete */ +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +/* Set the MII address register to write */ +writel (data, iobase +GETH_MDIO_DATA ); +writel (value, iobase +GETH_MDIO_ADDR ); + +/* Wait until any existing MII operation is complete */ +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +return 0 ; +} + +int sunxi_mdio_reset (void *iobase) +{ +writel ((4 <<2 ), iobase +GETH_MDIO_ADDR ); +return 0 ; +} + +void sunxi_set_link_mode (void *iobase,int duplex,int speed) +{ +unsigned int ctrl =readl (iobase +GETH_BASIC_CTL0 ); + +if (!duplex) + ctrl &= ~CTL0_DM ; +else + ctrl |=CTL0_DM ; + +switch (speed) { +case 1000 : + ctrl &= ~0x0C ; +break ; +case 100 : +case 10 : +default : + ctrl |=0x08 ; +if (speed ==100 ) + ctrl |=0x04 ; +else + ctrl &= ~0x04 ; +break ; + } + +writel (ctrl, iobase +GETH_BASIC_CTL0 ); +} + +void sunxi_mac_loopback (void *iobase,int enable) +{ +int reg; + + reg =readl (iobase +GETH_BASIC_CTL0 ); +if (enable) + reg |=0x02 ; +else + reg &= ~0x02 ; +writel (reg, iobase +GETH_BASIC_CTL0 ); +} + +void sunxi_flow_ctrl (void *iobase,int duplex,int fc,int pause) +{ +unsigned int flow =0 ; + +if (fc &FLOW_RX ) { + flow =readl (iobase +GETH_RX_CTL0 ); + flow |=0x10000 ; +writel (flow, iobase +GETH_RX_CTL0 ); + } + +if (fc &FLOW_TX ) { + flow =readl (iobase +GETH_TX_FLOW_CTL ); + flow |=0x00001 ; +writel (flow, iobase +GETH_TX_FLOW_CTL ); + } + +if (duplex) { + flow =readl (iobase +GETH_TX_FLOW_CTL ); + flow |= (pause <<4 ); +writel (flow, iobase +GETH_TX_FLOW_CTL ); + } +} + +int sunxi_int_status (void *iobase,struct geth_extra_stats *x) +{ +int ret =0 ; +/* read the status register (CSR5) */ +unsigned int intr_status; + + intr_status =readl (iobase +GETH_RGMII_STA ); +if (intr_status &RGMII_IRQ ) +readl (iobase +GETH_RGMII_STA ); + + intr_status =readl (iobase +GETH_INT_STA ); + +/* ABNORMAL interrupts */ +if (intr_status &TX_UNF_INT ) { + ret = tx_hard_error_bump_tc; + x->tx_undeflow_irq++; + } +if (intr_status &TX_TOUT_INT ) { + x->tx_jabber_irq++; + } +if (intr_status &RX_OVF_INT ) { + x->rx_overflow_irq++; + } +if (intr_status &RX_UA_INT ) { + x->rx_buf_unav_irq++; + } +if (intr_status &RX_STOP_INT ) { + x->rx_process_stopped_irq++; + } +if (intr_status &RX_TOUT_INT ) { + x->rx_watchdog_irq++; + } +if (intr_status &TX_EARLY_INT ) { + x->tx_early_irq++; + } +if (intr_status &TX_STOP_INT ) { + x->tx_process_stopped_irq++; + ret = tx_hard_error; + } + +/* TX/RX NORMAL interrupts */ +if (intr_status & (TX_INT |RX_INT |RX_EARLY_INT |TX_UA_INT )) { + x->normal_irq_n++; +if (intr_status & (TX_INT |RX_INT )) + ret = handle_tx_rx; + } +/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ +writel (intr_status &0x3FFF , iobase +GETH_INT_STA ); + +return ret; +} + +void sunxi_start_rx (void *iobase,unsigned long rxbase) +{ +unsigned int value; + +/* Write the base address of Rx descriptor lists into registers */ +writel (rxbase, iobase +GETH_RX_DESC_LIST ); + + value =readl (iobase +GETH_RX_CTL1 ); + value |=0x40000000 ; +writel (value, iobase +GETH_RX_CTL1 ); +} + +void sunxi_stop_rx (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_RX_CTL1 ); + value &= ~0x40000000 ; +writel (value, iobase +GETH_RX_CTL1 ); +} + +void sunxi_start_tx (void *iobase,unsigned long txbase) +{ +unsigned int value; + +/* Write the base address of Tx descriptor lists into registers */ +writel (txbase, iobase +GETH_TX_DESC_LIST ); + + value =readl (iobase +GETH_TX_CTL1 ); + value |=0x40000000 ; +writel (value, iobase +GETH_TX_CTL1 ); +} + +void sunxi_stop_tx (void *iobase) +{ +unsigned int value =readl (iobase +GETH_TX_CTL1 ); + + value &= ~0x40000000 ; +writel (value, iobase +GETH_TX_CTL1 ); +} + +static int sunxi_dma_init (void *iobase) +{ +unsigned int value; + +/* Burst should be 8 */ + value = (8 <<24 ); + +#ifdef CONFIG_GMAC_DA + value |=RX_TX_PRI ;/* Rx has priority over tx */ +#endif +writel (value, iobase +GETH_BASIC_CTL1 ); + +/* Mask interrupts by writing to CSR7 */ +writel (RX_INT |TX_UNF_INT , iobase +GETH_INT_EN ); + +return 0 ; +} + +int sunxi_mac_init (void *iobase,int txmode,int rxmode) +{ +unsigned int value; + +sunxi_dma_init (iobase); + +/* Initialize the core component */ + value =readl (iobase +GETH_TX_CTL0 ); + value |= (1 <<30 );/* Jabber Disable */ +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value |= (1 <<27 );/* Enable CRC & IPv4 Header Checksum */ + value |= (1 <<28 );/* Automatic Pad/CRC Stripping */ + value |= (1 <<29 );/* Jumbo Frame Enable */ +writel (value, iobase +GETH_RX_CTL0 ); + +writel ((hwdev.mdc_div <<20 ), iobase +GETH_MDIO_ADDR );/* MDC_DIV_RATIO */ + +/* Set the Rx&Tx mode */ + value =readl (iobase +GETH_TX_CTL1 ); +if (txmode ==SF_DMA_MODE ) { +/* Transmit COE type 2 cannot be done in cut-through mode. */ + value |=TX_MD ; +/* Operating on second frame increase the performance +* especially when transmit store-and-forward is used. +*/ + value |=TX_NEXT_FRM ; + }else { + value &= ~TX_MD ; + value &= ~TX_TH ; +/* Set the transmit threshold */ +if (txmode <=64 ) + value |=0x00000000 ; +else if (txmode <=128 ) + value |=0x00000100 ; +else if (txmode <=192 ) + value |=0x00000200 ; +else + value |=0x00000300 ; + } +writel (value, iobase +GETH_TX_CTL1 ); + + value =readl (iobase +GETH_RX_CTL1 ); +if (rxmode ==SF_DMA_MODE ) { + value |=RX_MD ; + }else { + value &= ~RX_MD ; + value &= ~RX_TH ; +if (rxmode <=32 ) + value |=0x10 ; +else if (rxmode <=64 ) + value |=0x00 ; +else if (rxmode <=96 ) + value |=0x20 ; +else + value |=0x30 ; + } + +/* Forward frames with error and undersized good frame. */ + value |= (RX_ERR_FRM |RX_RUNT_FRM ); + +writel (value, iobase +GETH_RX_CTL1 ); + +return 0 ; +} + +void sunxi_hash_filter (void *iobase,unsigned long low,unsigned long high) +{ +writel (high, iobase +GETH_RX_HASH0 ); +writel (low, iobase +GETH_RX_HASH1 ); +} + +void sunxi_set_filter (void *iobase,unsigned long flags) +{ +int tmp_flags =0 ; + + tmp_flags |= ((flags >>31 ) | + ((flags >>9 ) &0x00000002 ) | + ((flags <<1 ) &0x00000010 ) | + ((flags >>3 ) &0x00000060 ) | + ((flags <<7 ) &0x00000300 ) | + ((flags <<6 ) &0x00003000 ) | + ((flags <<12 ) &0x00030000 ) | + (flags <<31 )); + +writel (tmp_flags, iobase +GETH_RX_FRM_FLT ); +} + +void sunxi_set_umac (void *iobase,unsigned char *addr,int index) +{ +unsigned long data; + + data = (addr[5 ] <<8 ) | addr[4 ]; +writel (data, iobase +GETH_ADDR_HI (index)); + data = (addr[3 ] <<24 ) | (addr[2 ] <<16 ) | (addr[1 ] <<8 ) | addr[0 ]; +writel (data, iobase +GETH_ADDR_LO (index)); +} + +void sunxi_mac_enable (void *iobase) +{ +unsigned long value; + + value =readl (iobase +GETH_TX_CTL0 ); + value |= (1 <<31 ); +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value |= (1 <<31 ); +writel (value, iobase +GETH_RX_CTL0 ); +} + +void sunxi_mac_disable (void *iobase) +{ +unsigned long value; + + value =readl (iobase +GETH_TX_CTL0 ); + value &= ~(1 <<31 ); +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value &= ~(1 <<31 ); +writel (value, iobase +GETH_RX_CTL0 ); +} + +void sunxi_tx_poll (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_TX_CTL1 ); +writel (value |0x80000000 , iobase +GETH_TX_CTL1 ); +} + +void sunxi_rx_poll (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_RX_CTL1 ); +writel (value |0x80000000 , iobase +GETH_RX_CTL1 ); +} + +void sunxi_int_enable (void *iobase) +{ +writel (RX_INT |TX_UNF_INT , iobase +GETH_INT_EN ); +} + +void sunxi_int_disable (void *iobase) +{ +writel (0 , iobase +GETH_INT_EN ); +} + +void desc_buf_set (struct dma_desc *desc,unsigned long paddr,int size) +{ + desc->desc1.all &= (~((1 <<11 ) -1 )); + desc->desc1.all |= (size & ((1 <<11 ) -1 )); + desc->desc2 = paddr; +} + +void desc_set_own (struct dma_desc *desc) +{ + desc->desc0.all |=0x80000000 ; +} + +void desc_tx_close (struct dma_desc *first,struct dma_desc *end,int csum_insert) +{ +struct dma_desc *desc = first; + + first->desc1.tx.first_sg =1 ; + end->desc1.tx.last_seg =1 ; + end->desc1.tx.interrupt =1 ; + +if (csum_insert) +do { + desc->desc1.tx.cic =3 ; + desc++; + }while (desc <= end); +} + +void desc_init (struct dma_desc *desc) +{ + desc->desc1.all =0 ; + desc->desc2 =0 ; + + desc->desc1.all |= (1 <<24 ); +} + +int desc_get_tx_status (struct dma_desc *desc,struct geth_extra_stats *x) +{ +int ret =0 ; + +if (desc->desc0.tx.under_err) { + x->tx_underflow++; + ret =-1 ; + } +if (desc->desc0.tx.no_carr) { + x->tx_carrier++; + ret =-1 ; + } +if (desc->desc0.tx.loss_carr) { + x->tx_losscarrier++; + ret =-1 ; + } + +#if 0 +if ((desc->desc0.tx.ex_deferral) || + (desc->desc0.tx.ex_coll) || + (desc->desc0.tx.late_coll)) + stats->collisions += desc->desc0.tx.coll_cnt; +#endif + +if (desc->desc0.tx.deferred) + x->tx_deferred++; + +return ret; +} + +int desc_buf_get_len (struct dma_desc *desc) +{ +return (desc->desc1.all & ((1 <<11 ) -1 )); +} + +int desc_buf_get_addr (struct dma_desc *desc) +{ +return desc->desc2; +} + +int desc_rx_frame_len (struct dma_desc *desc) +{ +return desc->desc0.rx.frm_len; +} + +int desc_get_rx_status (struct dma_desc *desc,struct geth_extra_stats *x) +{ +int ret = good_frame; + +if (desc->desc0.rx.last_desc ==0 ) { +return discard_frame; + } + +if (desc->desc0.rx.err_sum) { +if (desc->desc0.rx.desc_err) + x->rx_desc++; + +if (desc->desc0.rx.sou_filter) + x->sa_filter_fail++; + +if (desc->desc0.rx.over_err) + x->overflow_error++; + +if (desc->desc0.rx.ipch_err) + x->ipc_csum_error++; + +if (desc->desc0.rx.late_coll) + x->rx_collision++; + +if (desc->desc0.rx.crc_err) + x->rx_crc++; + + ret = discard_frame; + } + +if (desc->desc0.rx.len_err) { + ret = discard_frame; + } +if (desc->desc0.rx.mii_err) { + ret = discard_frame; + } + +return ret; +} + +int desc_get_own (struct dma_desc *desc) +{ +return desc->desc0.all &0x80000000 ; +} + +int desc_get_tx_ls (struct dma_desc *desc) +{ +return desc->desc1.tx.last_seg; +} + +int sunxi_geth_register (void *iobase,int version,unsigned int div) +{ + hwdev.ver = version; + hwdev.iobase = iobase; + hwdev.mdc_div = div; + +return 0 ; +} + +int sunxi_mac_reset (void *iobase,void (*delay)(int ),int n) +{ +unsigned int value; + +/* DMA SW reset */ + value =readl (iobase +GETH_BASIC_CTL1 ); + value |=SOFT_RST ; +writel (value, iobase +GETH_BASIC_CTL1 ); + +delay (n); + +return !!(readl (iobase +GETH_BASIC_CTL1 ) &SOFT_RST ); +}drivers/net/ethernet/allwinnertmp/sunxi-gmac.c new file +2240
-0@@ -0,0 +1,2240 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac.c +* +* Copyright © 2016-2018, fuzhaoke +* Author: fuzhaoke <[email protected]> +* +* This file is provided under a dual BSD/GPL license. When using or +* redistributing this file, you may do so under either license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +//#include <linux/clk.h> +//#include <linux/clk-provider.h> +#include <linux/mii.h> +#include <linux/gpio.h> +#include <linux/crc32.h> +#include <linux/skbuff.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +//#include <linux/pinctrl/consumer.h> +//#include <linux/pinctrl/pinctrl.h> +#include <linux/crypto.h> +#include <crypto/algapi.h> +#include <crypto/hash.h> +#include <linux/err.h> +#include <linux/scatterlist.h> +//#include <linux/regulator/consumer.h> +#include <linux/of_net.h> +//#include <linux/of_gpio.h> +#include <linux/io.h> +//#include <linux/sunxi-sid.h> +//#include <linux/sunxi-gpio.h> +//#include <linux/reset.h> +#include "sunxi-gmac.h" + +#define SUNXI_GMAC_VERSION "1.0.0" + +#define DMA_DESC_RX 256 +#define DMA_DESC_TX 256 +#define BUDGET (dma_desc_rx / 4) +#define TX_THRESH (dma_desc_tx / 4) + +#define HASH_TABLE_SIZE 64 +#define MAX_BUF_SZ (SZ_2K - 1) + +#define POWER_CHAN_NUM 3 + +#undef PKT_DEBUG +#undef DESC_PRINT + +#define circ_cnt (head, tail, size) (((head) > (tail)) ? \ + ((head) - (tail)) : \ + ((head) - (tail)) & ((size) - 1)) + +#define circ_space (head, tail, size) circ_cnt((tail), ((head) + 1), (size)) + +#define circ_inc (n, s) (((n) + 1) % (s)) + +#define GETH_MAC_ADDRESS "00:00:00:00:00:00" +static char *mac_str =GETH_MAC_ADDRESS ; +module_param (mac_str, charp,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (mac_str,"MAC Address String.(xx:xx:xx:xx:xx:xx)" ); + +static int rxmode =1 ; +module_param (rxmode, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (rxmode,"DMA threshold control value" ); + +static int txmode =1 ; +module_param (txmode, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (txmode,"DMA threshold control value" ); + +static int pause =0x400 ; +module_param (pause, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (pause,"Flow Control Pause Time" ); + +#define TX_TIMEO 5000 +static int watchdog =TX_TIMEO ; +module_param (watchdog, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"Transmit timeout in milliseconds" ); + +static int dma_desc_rx =DMA_DESC_RX ; +module_param (dma_desc_rx, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"The number of receive's descriptors" ); + +static int dma_desc_tx =DMA_DESC_TX ; +module_param (dma_desc_tx, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"The number of transmit's descriptors" ); + +/* - 0: Flow Off +* - 1: Rx Flow +* - 2: Tx Flow +* - 3: Rx & Tx Flow +*/ +static int flow_ctrl; +module_param (flow_ctrl, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (flow_ctrl,"Flow control [0: off, 1: rx, 2: tx, 3: both]" ); + +struct geth_priv { +struct dma_desc *dma_tx; +struct sk_buff **tx_sk; +unsigned int tx_clean; +unsigned int tx_dirty; +dma_addr_t dma_tx_phy; + +unsigned long buf_sz; + +struct dma_desc *dma_rx; +struct sk_buff **rx_sk; +unsigned int rx_clean; +unsigned int rx_dirty; +dma_addr_t dma_rx_phy; + +struct net_device *ndev; +struct device *dev; +struct napi_struct napi; + +struct geth_extra_stats xstats; + +struct mii_bus *mii; +int link; +int speed; +int duplex; +#define INT_PHY 0 +#define EXT_PHY 1 +int phy_ext; +phy_interface_t phy_interface; + +void __iomem *base; +void __iomem *base_phy; +/* +struct clk *geth_clk; +struct clk *ephy_clk; +struct reset_control *reset; +struct pinctrl *pinctrl; +*/ +struct regulator *gmac_power[POWER_CHAN_NUM ]; +bool is_suspend; +int phyrst; +u8 rst_active_low; +/* definition spinlock */ +spinlock_t lock; +spinlock_t tx_lock; + +/* whether using ephy_clk */ +int use_ephy_clk; +int phy_addr; + +/* adjust transmit clock delay, value: 0~7 */ +/* adjust receive clock delay, value: 0~31 */ +unsigned int tx_delay; +unsigned int rx_delay; + +/* resume work */ +struct work_struct eth_work; +}; + +static u64 geth_dma_mask =DMA_BIT_MASK (32 ); + +void sunxi_udelay (int n) +{ +udelay (n); +} + +static int geth_stop (struct net_device *ndev); +static int geth_open (struct net_device *ndev); +static void geth_tx_complete (struct geth_priv *priv); +static void geth_rx_refill (struct net_device *ndev); + +#ifdef CONFIG_GETH_ATTRS +static ssize_t adjust_bgs_show (struct device *dev,struct device_attribute *attr,char *buf) +{ +int value =0 ; +u32 efuse_value; +struct net_device *ndev =to_net_dev (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (priv->phy_ext ==INT_PHY ) { + value =readl (priv->base_phy) >>28 ; +if (sunxi_efuse_read (EFUSE_OEM_NAME , &efuse_value) !=0 ) +pr_err ("get PHY efuse fail!\n" ); + else +#if IS_ENABLED (CONFIG_ARCH_SUN50IW2 ) + value = value - ((efuse_value >>24 ) &0x0F ); +#else +pr_warn ("miss config come from efuse!\n" ); +#endif + } + +return sprintf (buf,"bgs: %d\n" , value); +} + +static ssize_t adjust_bgs_write (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +unsigned int out =0 ; +struct net_device *ndev =to_net_dev (dev); +struct geth_priv *priv =netdev_priv (ndev); +u32 clk_value =readl (priv->base_phy); +u32 efuse_value; + + out =simple_strtoul (buf,NULL ,10 ); + +if (priv->phy_ext ==INT_PHY ) { + clk_value &= ~(0xF <<28 ); +if (sunxi_efuse_read (EFUSE_OEM_NAME , &efuse_value) !=0 ) +pr_err ("get PHY efuse fail!\n" ); + else +#if IS_ENABLED (CONFIG_ARCH_SUN50IW2 ) + clk_value |= (((efuse_value >>24 ) &0x0F ) + out) <<28 ; +#else +pr_warn ("miss config come from efuse!\n" ); +#endif + } + +writel (clk_value, priv->base_phy); + +return count; +} + +static struct device_attribute adjust_reg[] = { +__ATTR (adjust_bgs,0664 , adjust_bgs_show, adjust_bgs_write), +}; + +static int geth_create_attrs (struct net_device *ndev) +{ +int j, ret; + +for (j =0 ; j <ARRAY_SIZE (adjust_reg); j++) { + ret =device_create_file (&ndev->dev, &adjust_reg[j]); +if (ret) + goto sysfs_failed; + } + goto succeed; + +sysfs_failed: +while (j--) +device_remove_file (&ndev->dev, &adjust_reg[j]); +succeed: +return ret; +} +#endif + +#ifdef DEBUG +static void desc_print (struct dma_desc *desc,int size) +{ +#ifdef DESC_PRINT +int i; + +for (i =0 ; i < size; i++) { +u32 *x = (u32 *)(desc + i); + +pr_info ("\t%d [0x%08lx]: %08x %08x %08x %08x\n" , + i, (unsigned long )(&desc[i]), + x[0 ], x[1 ], x[2 ], x[3 ]); + } +pr_info ("\n" ); +#endif +} +#endif + +static ssize_t extra_tx_stats_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"tx_underflow: %lu\ntx_carrier: %lu\n" +"tx_losscarrier: %lu\nvlan_tag: %lu\n" +"tx_deferred: %lu\ntx_vlan: %lu\n" +"tx_jabber: %lu\ntx_frame_flushed: %lu\n" +"tx_payload_error: %lu\ntx_ip_header_error: %lu\n\n" , + priv->xstats.tx_underflow, priv->xstats.tx_carrier, + priv->xstats.tx_losscarrier, priv->xstats.vlan_tag, + priv->xstats.tx_deferred, priv->xstats.tx_vlan, + priv->xstats.tx_jabber, priv->xstats.tx_frame_flushed, + priv->xstats.tx_payload_error, priv->xstats.tx_ip_header_error); +} +static DEVICE_ATTR(extra_tx_stats, 0444, extra_tx_stats_show, NULL); + +static ssize_t extra_rx_stats_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"rx_desc: %lu\nsa_filter_fail: %lu\n" +"overflow_error: %lu\nipc_csum_error: %lu\n" +"rx_collision: %lu\nrx_crc: %lu\n" +"dribbling_bit: %lu\nrx_length: %lu\n" +"rx_mii: %lu\nrx_multicast: %lu\n" +"rx_gmac_overflow: %lu\nrx_watchdog: %lu\n" +"da_rx_filter_fail: %lu\nsa_rx_filter_fail: %lu\n" +"rx_missed_cntr: %lu\nrx_overflow_cntr: %lu\n" +"rx_vlan: %lu\n\n" , + priv->xstats.rx_desc, priv->xstats.sa_filter_fail, + priv->xstats.overflow_error, priv->xstats.ipc_csum_error, + priv->xstats.rx_collision, priv->xstats.rx_crc, + priv->xstats.dribbling_bit, priv->xstats.rx_length, + priv->xstats.rx_mii, priv->xstats.rx_multicast, + priv->xstats.rx_gmac_overflow, priv->xstats.rx_length, + priv->xstats.da_rx_filter_fail, priv->xstats.sa_rx_filter_fail, + priv->xstats.rx_missed_cntr, priv->xstats.rx_overflow_cntr, + priv->xstats.rx_vlan); +} +static DEVICE_ATTR(extra_rx_stats, 0444, extra_rx_stats_show, NULL); + +static ssize_t gphy_test_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"Usage:\necho [0/1/2/3/4] > gphy_test\n" +"0 - Normal Mode\n" +"1 - Transmit Jitter Test\n" +"2 - Transmit Jitter Test(MASTER mode)\n" +"3 - Transmit Jitter Test(SLAVE mode)\n" +"4 - Transmit Distortion Test\n\n" ); +} + +static ssize_t gphy_test_store (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); +u16 value =0 ; +int ret =0 ; +u16 data =0 ; + +if (!dev) { +pr_err ("Argument is invalid\n" ); +return count; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return count; + } + + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_CTRL1000 ); + + ret =kstrtou16 (buf,0 , &value); +if (ret) +return ret; + +if (value >=0 && value <=4 ) { + data &= ~(0x7 <<13 ); + data |= value <<13 ; +sunxi_mdio_write (priv->base, priv->phy_addr,MII_CTRL1000 , data); +pr_info ("Set MII_CTRL1000(0x09) Reg: 0x%x\n" , data); + }else { +pr_info ("unknown value (%d)\n" , value); + } + +return count; +} + +static DEVICE_ATTR(gphy_test, 0664, gphy_test_show, gphy_test_store); + +static ssize_t mii_reg_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =NULL ; +struct geth_priv *priv =NULL ; + +if (dev ==NULL ) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + + ndev =dev_get_drvdata (dev); +if (ndev ==NULL ) { +pr_err ("Net device is null\n" ); +return 0 ; + } + + priv =netdev_priv (ndev); +if (priv ==NULL ) { +pr_err ("geth_priv is null\n" ); +return 0 ; + } + +if (!netif_running (ndev)) { +pr_warn ("eth is down!\n" ); +return 0 ; + } + +return sprintf (buf, +"Current MII Registers:\n" +"BMCR[0x%02x] = 0x%04x,\t\tBMSR[0x%02x] = 0x%04x,\t\tPHYSID1[0x%02x] = 0x%04x\n" +"PHYSID2[0x%02x] = 0x%04x,\t\tADVERTISE[0x%02x] = 0x%04x,\tLPA[0x%02x] = 0x%04x\n" +"EXPANSION[0x%02x] = 0x%04x,\tCTRL1000[0x%02x] = 0x%04x,\tSTAT1000[0x%02x] = 0x%04x\n" , +MII_BMCR ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ), +MII_BMSR ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMSR ), +MII_PHYSID1 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_PHYSID1 ), +MII_PHYSID2 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_PHYSID2 ), +MII_ADVERTISE ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_ADVERTISE ), +MII_LPA ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_LPA ), +MII_EXPANSION ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_EXPANSION ), +MII_CTRL1000 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_CTRL1000 ), +MII_STAT1000 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_STAT1000 )); +} +static DEVICE_ATTR(mii_reg, 0444, mii_reg_show, NULL); + +static ssize_t loopback_test_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +return sprintf (buf,"Usage:\necho [0/1/2] > loopback_test\n" +"0 - Normal Mode\n" +"1 - Mac loopback test mode\n" +"2 - Phy loopback test mode\n" ); +} + +static ssize_t loopback_test_store (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct net_device *ndev =NULL ; +struct geth_priv *priv =NULL ; +u16 value =0 ; +int ret =0 ; +u16 data =0 ; + +if (dev ==NULL ) { +pr_err ("Argment is invalid\n" ); +return count; + } + + ndev =dev_get_drvdata (dev); +if (ndev ==NULL ) { +pr_err ("Net device is null\n" ); +return count; + } + + priv =netdev_priv (ndev); +if (priv ==NULL ) { +pr_err ("geth_priv is null\n" ); +return count; + } + +if (!netif_running (ndev)) { +pr_warn ("eth is down!\n" ); +return count; + } + + ret =kstrtou16 (buf,0 , &value); +if (ret) +return ret; + +if (value ==0 ) {/* normal mode */ +/* clear mac loopback */ +sunxi_mac_loopback (priv->base,0 ); + +/* clear phy loopback */ + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data & ~BMCR_LOOPBACK ); + }else if (value ==1 ) {/* mac loopback test mode */ + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data & ~BMCR_LOOPBACK ); + +sunxi_mac_loopback (priv->base,1 ); + }else if (value ==2 ) {/* phy loopback test mode */ +sunxi_mac_loopback (priv->base,0 ); + + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data |BMCR_LOOPBACK ); + }else { +pr_err ("Undefined value (%d)\n" , value); + } + +return count; +} +static DEVICE_ATTR(loopback_test, 0664, loopback_test_show, loopback_test_store); + +static int geth_power_on (struct geth_priv *priv) +{ +int value; + + value =readl (priv->base_phy); +if (priv->phy_ext ==INT_PHY ) { + value |= (1 <<15 ); + value &= ~(1 <<16 ); + value |= (3 <<17 ); + }else { + value &= ~(1 <<15 ); +/* +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +if (regulator_enable(priv->gmac_power[i]) != 0) { +pr_err("gmac-power%d enable error\n", i); +return -EINVAL; +} +} +*/ + } + +writel (value, priv->base_phy); + +return 0 ; +} + +static void geth_power_off (struct geth_priv *priv) +{ +int value; + +if (priv->phy_ext ==INT_PHY ) { + value =readl (priv->base_phy); + value |= (1 <<16 ); +writel (value, priv->base_phy); + }else { +/* +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_disable(priv->gmac_power[i]); +} +*/ + } +} + +/* PHY interface operations */ +static int geth_mdio_read (struct mii_bus *bus,int phyaddr,int phyreg) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +return (int )sunxi_mdio_read (priv->base, phyaddr, phyreg); +} + +static int geth_mdio_write (struct mii_bus *bus,int phyaddr, +int phyreg,u16 data) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +sunxi_mdio_write (priv->base, phyaddr, phyreg, data); + +return 0 ; +} + +static int geth_mdio_reset (struct mii_bus *bus) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +return sunxi_mdio_reset (priv->base); +} + +static void geth_adjust_link (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; +unsigned long flags; +int new_state =0 ; + +if (!phydev) +return ; + +spin_lock_irqsave (&priv->lock, flags); +if (phydev->link) { +/* Now we make sure that we can be in full duplex mode. +* If not, we operate in half-duplex mode. +*/ +if (phydev->duplex != priv->duplex) { + new_state =1 ; + priv->duplex = phydev->duplex; + } +/* Flow Control operation */ +if (phydev->pause) +sunxi_flow_ctrl (priv->base, phydev->duplex, + flow_ctrl, pause); + +if (phydev->speed != priv->speed) { + new_state =1 ; + priv->speed = phydev->speed; + } + +if (priv->link ==0 ) { + new_state =1 ; + priv->link = phydev->link; + } + +if (new_state) +sunxi_set_link_mode (priv->base, priv->duplex, priv->speed); + +#ifdef LOOPBACK_DEBUG + phydev->state =PHY_FORCING ; +#endif + + }else if (priv->link != phydev->link) { + new_state =1 ; + priv->link =0 ; + priv->speed =0 ; + priv->duplex =-1 ; + } + +if (new_state) +phy_print_status (phydev); + +spin_unlock_irqrestore (&priv->lock, flags); +} + +static int geth_phy_init (struct net_device *ndev) +{ +int value; +struct mii_bus *new_bus; +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; + +/* Fixup the phy interface type */ +if (priv->phy_ext ==INT_PHY ) { + priv->phy_interface =PHY_INTERFACE_MODE_MII ; + }else { +/* If config gpio to reset the phy device, we should reset it */ +/* +if (gpio_is_valid(priv->phyrst)) { +gpio_direction_output(priv->phyrst, +priv->rst_active_low); +msleep(50); +gpio_direction_output(priv->phyrst, +!priv->rst_active_low); +msleep(50); +} +*/ + } + +if (priv->is_suspend && phydev) + goto resume; + + new_bus =mdiobus_alloc (); +if (!new_bus) { +netdev_err (ndev,"Failed to alloc new mdio bus\n" ); +return -ENOMEM ; + } + + new_bus->name =dev_name (priv->dev); + new_bus->read = &geth_mdio_read; + new_bus->write = &geth_mdio_write; + new_bus->reset = &geth_mdio_reset; +snprintf (new_bus->id,MII_BUS_ID_SIZE ,"%s-%x" , new_bus->name,0 ); + + new_bus->parent = priv->dev; + new_bus->priv = ndev; + +if (mdiobus_register (new_bus)) { +pr_err ("%s: Cannot register as MDIO bus\n" , new_bus->name); + goto reg_fail; + } + + priv->mii = new_bus; + + { +int addr; + +for (addr =0 ; addr <PHY_MAX_ADDR ; addr++) { +struct phy_device *phydev_tmp =mdiobus_get_phy (new_bus, addr); + +if (phydev_tmp && (phydev_tmp->phy_id !=0x00 )) { + phydev = phydev_tmp; + priv->phy_addr = addr; +break ; + } + } + } + +if (!phydev) { +netdev_err (ndev,"No PHY found!\n" ); + goto err; + } + + phydev->irq =PHY_POLL ; + + value =phy_connect_direct (ndev, phydev, &geth_adjust_link, priv->phy_interface); +if (value) { +netdev_err (ndev,"Could not attach to PHY\n" ); + goto err; + }else { +netdev_info (ndev,"%s: Type(%d) PHY ID %08x at %d IRQ %s (%s)\n" , + ndev->name, phydev->interface, phydev->phy_id, + phydev->mdio.addr,"poll" ,dev_name (&phydev->mdio.dev)); + } + +//phydev->supported &= PHY_GBIT_FEATURES; + phydev->is_gigabit_capable =1 ; +//phydev->advertising = phydev->supported; + +resume: +phy_write (phydev,MII_BMCR ,BMCR_RESET ); +while (BMCR_RESET &phy_read (phydev,MII_BMCR )) +msleep (30 ); + + value =phy_read (phydev,MII_BMCR ); +phy_write (phydev,MII_BMCR , (value & ~BMCR_PDOWN )); + +if (priv->phy_ext ==INT_PHY ) { +/* EPHY Initial */ +phy_write (phydev,0x1f ,0x0100 );/* switch to page 1 */ +phy_write (phydev,0x12 ,0x4824 );/* Disable APS */ +phy_write (phydev,0x1f ,0x0200 );/* switchto page 2 */ +phy_write (phydev,0x18 ,0x0000 );/* PHYAFE TRX optimization */ +phy_write (phydev,0x1f ,0x0600 );/* switchto page 6 */ +phy_write (phydev,0x14 ,0x708F );/* PHYAFE TX optimization */ +phy_write (phydev,0x19 ,0x0000 ); +phy_write (phydev,0x13 ,0xf000 );/* PHYAFE RX optimization */ +phy_write (phydev,0x15 ,0x1530 ); +phy_write (phydev,0x1f ,0x0800 );/* switch to page 8 */ +phy_write (phydev,0x18 ,0x00bc );/* PHYAFE TRX optimization */ +phy_write (phydev,0x1f ,0x0100 );/* switchto page 1 */ +/* reg 0x17 bit3,set 0 to disable iEEE */ +phy_write (phydev,0x17 ,phy_read (phydev,0x17 ) & (~(1 <<3 ))); +phy_write (phydev,0x1f ,0x0000 );/* switch to page 0 */ + } +if (priv->is_suspend) +phy_init_hw (phydev); + +return 0 ; + +err: +mdiobus_unregister (new_bus); +reg_fail: +mdiobus_free (new_bus); + +return -EINVAL ; +} + +static int geth_phy_release (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; +int value =0 ; + +/* Stop and disconnect the PHY */ +if (phydev) +phy_stop (phydev); + + priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; + +if (phydev) { + value =phy_read (phydev,MII_BMCR ); +phy_write (phydev,MII_BMCR , (value |BMCR_PDOWN )); + } + +if (priv->is_suspend) +return 0 ; + +if (phydev) { +phy_disconnect (phydev); + ndev->phydev =NULL ; + } + +if (priv->mii) { +mdiobus_unregister (priv->mii); + priv->mii->priv =NULL ; +mdiobus_free (priv->mii); + priv->mii =NULL ; + } + +return 0 ; +} + +static void geth_rx_refill (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct dma_desc *desc; +struct sk_buff *sk =NULL ; +dma_addr_t paddr; + +while (circ_space (priv->rx_clean, priv->rx_dirty, dma_desc_rx) >0 ) { +int entry = priv->rx_clean; + +/* Find the dirty's desc and clean it */ + desc = priv->dma_rx + entry; + +if (priv->rx_sk[entry] ==NULL ) { + sk =netdev_alloc_skb_ip_align (ndev, priv->buf_sz); + +if (unlikely (sk ==NULL )) +break ; + + priv->rx_sk[entry] = sk; + paddr =dma_map_single (priv->dev, sk->data, + priv->buf_sz,DMA_FROM_DEVICE ); +desc_buf_set (desc, paddr, priv->buf_sz); + } + +/* sync memery */ +wmb (); +desc_set_own (desc); + priv->rx_clean =circ_inc (priv->rx_clean, dma_desc_rx); + } +} + +/* geth_dma_desc_init - initialize the RX/TX descriptor list +* @ndev: net device structure +* Description: initialize the list for dma. +*/ +static int geth_dma_desc_init (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int buf_sz; + + priv->rx_sk =kzalloc (sizeof (struct sk_buff *) * dma_desc_rx, +GFP_KERNEL ); +if (!priv->rx_sk) +return -ENOMEM ; + + priv->tx_sk =kzalloc (sizeof (struct sk_buff *) * dma_desc_tx, +GFP_KERNEL ); +if (!priv->tx_sk) + goto tx_sk_err; + +/* Set the size of buffer depend on the MTU & max buf size */ + buf_sz =MAX_BUF_SZ ; + + priv->dma_tx =dma_alloc_coherent (priv->dev, + dma_desc_tx * +sizeof (struct dma_desc ), + &priv->dma_tx_phy, +GFP_KERNEL ); +if (!priv->dma_tx) + goto dma_tx_err; + + priv->dma_rx =dma_alloc_coherent (priv->dev, + dma_desc_rx * +sizeof (struct dma_desc ), + &priv->dma_rx_phy, +GFP_KERNEL ); +if (!priv->dma_rx) + goto dma_rx_err; + + priv->buf_sz = buf_sz; + +return 0 ; + +dma_rx_err: +dma_free_coherent (priv->dev, dma_desc_rx *sizeof (struct dma_desc ), + priv->dma_tx, priv->dma_tx_phy); +dma_tx_err: +kfree (priv->tx_sk); +tx_sk_err: +kfree (priv->rx_sk); + +return -ENOMEM ; +} + +static void geth_free_rx_sk (struct geth_priv *priv) +{ +int i; + +for (i =0 ; i < dma_desc_rx; i++) { +if (priv->rx_sk[i] !=NULL ) { +struct dma_desc *desc = priv->dma_rx + i; + +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc), +DMA_FROM_DEVICE ); +dev_kfree_skb_any (priv->rx_sk[i]); + priv->rx_sk[i] =NULL ; + } + } +} + +static void geth_free_tx_sk (struct geth_priv *priv) +{ +int i; + +for (i =0 ; i < dma_desc_tx; i++) { +if (priv->tx_sk[i] !=NULL ) { +struct dma_desc *desc = priv->dma_tx + i; + +if (desc_buf_get_addr (desc)) +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc), +DMA_TO_DEVICE ); +dev_kfree_skb_any (priv->tx_sk[i]); + priv->tx_sk[i] =NULL ; + } + } +} + +static void geth_free_dma_desc (struct geth_priv *priv) +{ +/* Free the region of consistent memory previously allocated for the DMA */ +dma_free_coherent (priv->dev, dma_desc_tx *sizeof (struct dma_desc ), + priv->dma_tx, priv->dma_tx_phy); +dma_free_coherent (priv->dev, dma_desc_rx *sizeof (struct dma_desc ), + priv->dma_rx, priv->dma_rx_phy); + +kfree (priv->rx_sk); +kfree (priv->tx_sk); +} + +#if IS_ENABLED (CONFIG_PM ) +/* +static int geth_select_gpio_state(struct pinctrl *pctrl, char *name) +{ +int ret = 0; +struct pinctrl_state *pctrl_state = NULL; + +pctrl_state = pinctrl_lookup_state(pctrl, name); +if (IS_ERR(pctrl_state)) { +pr_err("gmac pinctrl_lookup_state(%s) failed! return %p\n", +name, pctrl_state); +return -EINVAL; +} + +ret = pinctrl_select_state(pctrl, pctrl_state); +if (ret < 0) +pr_err("gmac pinctrl_select_state(%s) failed! return %d\n", +name, ret); + +return ret; +} +*/ +static int geth_suspend (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +cancel_work_sync (&priv->eth_work); + +if (!ndev || !netif_running (ndev)) +return 0 ; + + priv->is_suspend = true; + +spin_lock (&priv->lock); +netif_device_detach (ndev); +spin_unlock (&priv->lock); + +geth_stop (ndev); +/* +if (priv->phy_ext == EXT_PHY) + +geth_select_gpio_state(priv->pinctrl, PINCTRL_STATE_SLEEP); +*/ +return 0 ; +} + +static void geth_resume_work (struct work_struct *work) +{ + struct geth_priv *priv = container_of(work, struct geth_priv, eth_work); +struct net_device *ndev = priv->ndev; +int ret =0 ; + +if (!netif_running (ndev)) +return ; +/* +if (priv->phy_ext == EXT_PHY) +geth_select_gpio_state(priv->pinctrl, PINCTRL_STATE_DEFAULT); +*/ +spin_lock (&priv->lock); +netif_device_attach (ndev); +spin_unlock (&priv->lock); + +#if IS_ENABLED (CONFIG_SUNXI_EPHY ) +if (!ephy_is_enable ()) { +pr_info ("[geth_resume] ephy is not enable, waiting...\n" ); +msleep (2000 ); +if (!ephy_is_enable ()) { +netdev_err (ndev,"Wait for ephy resume timeout.\n" ); +return ; + } + } +#endif + + ret =geth_open (ndev); +if (!ret) + priv->is_suspend = false; +} + +static void geth_resume (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +schedule_work (&priv->eth_work); +} + +static int geth_freeze (struct device *dev) +{ +return 0 ; +} + +static int geth_restore (struct device *dev) +{ +return 0 ; +} + +static const struct dev_pm_ops geth_pm_ops = { + .complete = geth_resume, + .prepare = geth_suspend, + .suspend =NULL , + .resume =NULL , + .freeze = geth_freeze, + .restore = geth_restore, +}; +#else +static const struct dev_pm_ops geth_pm_ops; +#endif /* CONFIG_PM */ + +#define sunxi_get_soc_chipid (x) {} +static void geth_chip_hwaddr (u8 *addr) +{ +#define MD5_SIZE 16 +#define CHIP_SIZE 16 + +struct crypto_ahash *tfm; +struct ahash_request *req; +struct scatterlist sg; +u8 result[MD5_SIZE ]; +u8 chipid[CHIP_SIZE ]; +int i =0 ; +int ret =-1 ; + +memset (chipid,0 ,sizeof (chipid)); +memset (result,0 ,sizeof (result)); + +sunxi_get_soc_chipid ((u8 *)chipid); + + tfm =crypto_alloc_ahash ("md5" ,0 ,CRYPTO_ALG_ASYNC ); +if (IS_ERR (tfm)) { +pr_err ("Failed to alloc md5\n" ); +return ; + } + + req =ahash_request_alloc (tfm,GFP_KERNEL ); +if (!req) + goto out; + +ahash_request_set_callback (req,0 ,NULL ,NULL ); + + ret =crypto_ahash_init (req); +if (ret) { +pr_err ("crypto_ahash_init() failed\n" ); + goto out; + } + +sg_init_one (&sg, chipid,sizeof (chipid)); +ahash_request_set_crypt (req, &sg, result,sizeof (chipid)); + ret =crypto_ahash_update (req); +if (ret) { +pr_err ("crypto_ahash_update() failed for id\n" ); + goto out; + } + + ret =crypto_ahash_final (req); +if (ret) { +pr_err ("crypto_ahash_final() failed for result\n" ); + goto out; + } + +ahash_request_free (req); + +/* Choose md5 result's [0][2][4][6][8][10] byte as mac address */ +for (i =0 ; i <ETH_ALEN ; i++) + addr[i] = result[2 * i]; + addr[0 ] &=0xfe ;/* clear multicast bit */ + addr[0 ] |=0x02 ;/* set local assignment bit (IEEE802) */ + +out: +crypto_free_ahash (tfm); +} + +static void geth_check_addr (struct net_device *ndev,unsigned char *mac) +{ +int i; +char *p = mac; + +if (!is_valid_ether_addr (ndev->dev_addr)) { +for (i =0 ; i <ETH_ALEN ; i++, p++) + ndev->dev_addr[i] =simple_strtoul (p, &p,16 ); + +if (!is_valid_ether_addr (ndev->dev_addr)) +geth_chip_hwaddr (ndev->dev_addr); + +if (!is_valid_ether_addr (ndev->dev_addr)) { +random_ether_addr (ndev->dev_addr); +pr_warn ("%s: Use random mac address\n" , ndev->name); + } + } +} + +static int geth_clk_enable (struct geth_priv *priv) +{ +int ret; +phy_interface_t phy_interface =0 ; +u32 clk_value; +/*u32 efuse_value;*/ +/* +ret = reset_control_deassert(priv->reset); +if (ret) { +pr_err("deassert gmac rst failed!\n"); +return ret; +} + +ret = clk_prepare_enable(priv->geth_clk); +if (ret) { +pr_err("try to enable geth_clk failed!\n"); +goto assert_reset; +} + +if (((priv->phy_ext == INT_PHY) || priv->use_ephy_clk) +&& !IS_ERR_OR_NULL(priv->ephy_clk)) { +ret = clk_prepare_enable(priv->ephy_clk); +if (ret) { +pr_err("try to enable ephy_clk failed!\n"); +goto ephy_clk_disable; +} +} +*/ + phy_interface = priv->phy_interface; + + clk_value =readl (priv->base_phy); +if (phy_interface ==PHY_INTERFACE_MODE_RGMII ) + clk_value |=0x00000004 ; +else + clk_value &= (~0x00000004 ); + + clk_value &= (~0x00002003 ); +if (phy_interface ==PHY_INTERFACE_MODE_RGMII + || phy_interface ==PHY_INTERFACE_MODE_GMII ) + clk_value |=0x00000002 ; +else if (phy_interface ==PHY_INTERFACE_MODE_RMII ) + clk_value |=0x00002001 ; + +/*if (priv->phy_ext == INT_PHY) { +if (0 != sunxi_efuse_read(EFUSE_OEM_NAME, &efuse_value)) +pr_err("get PHY efuse fail!\n"); +else +#if IS_ENABLED(CONFIG_ARCH_SUN50IW2) +clk_value |= (((efuse_value >> 24) & 0x0F) + 3) << 28; +#else +pr_warn("miss config come from efuse!\n"); +#endif +}*/ + +/* Adjust Tx/Rx clock delay */ + clk_value &= ~(0x07 <<10 ); + clk_value |= ((priv->tx_delay &0x07 ) <<10 ); + clk_value &= ~(0x1F <<5 ); + clk_value |= ((priv->rx_delay &0x1F ) <<5 ); + +writel (clk_value, priv->base_phy); + +return 0 ; +/* +ephy_clk_disable: +clk_disable_unprepare(priv->ephy_clk); +assert_reset: +reset_control_assert(priv->reset); +*/ +return ret; +} + +static void geth_clk_disable (struct geth_priv *priv) +{ +/* +if (((priv->phy_ext == INT_PHY) || priv->use_ephy_clk) +&& !IS_ERR_OR_NULL(priv->ephy_clk)) +clk_disable_unprepare(priv->ephy_clk); + +clk_disable_unprepare(priv->geth_clk); +reset_control_assert(priv->reset); +*/ +} + +static void geth_tx_err (struct geth_priv *priv) +{ +netif_stop_queue (priv->ndev); + +sunxi_stop_tx (priv->base); + +geth_free_tx_sk (priv); +memset (priv->dma_tx,0 , dma_desc_tx *sizeof (struct dma_desc )); +desc_init_chain (priv->dma_tx, (unsigned long )priv->dma_tx_phy, dma_desc_tx); + priv->tx_dirty =0 ; + priv->tx_clean =0 ; +sunxi_start_tx (priv->base, priv->dma_tx_phy); + + priv->ndev->stats.tx_errors++; +netif_wake_queue (priv->ndev); +} + +static inline void geth_schedule (struct geth_priv *priv) +{ +if (likely (napi_schedule_prep (&priv->napi))) { +sunxi_int_disable (priv->base); +__napi_schedule (&priv->napi); + } +} + +static irqreturn_t geth_interrupt (int irq,void *dev_id) +{ +struct net_device *ndev = (struct net_device *)dev_id; +struct geth_priv *priv =netdev_priv (ndev); +int status; + +if (unlikely (!ndev)) { +pr_err ("%s: invalid ndev pointer\n" , __func__); +return IRQ_NONE ; + } + + status =sunxi_int_status (priv->base, (void *)(&priv->xstats)); + +if (likely (status == handle_tx_rx)) +geth_schedule (priv); +else if (unlikely (status == tx_hard_error_bump_tc)) +netdev_info (ndev,"Do nothing for bump tc\n" ); +else if (unlikely (status == tx_hard_error)) +geth_tx_err (priv); +else +netdev_info (ndev,"Do nothing.....\n" ); + +return IRQ_HANDLED ; +} + +static int geth_open (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +int ret =0 ; + + ret =geth_power_on (priv); +if (ret) { +netdev_err (ndev,"Power on is failed\n" ); + ret = -EINVAL ; + } + + ret =geth_clk_enable (priv); +if (ret) { +pr_err ("%s: clk enable is failed\n" , __func__); + ret = -EINVAL ; + } + +netif_carrier_off (ndev); + + ret =geth_phy_init (ndev); +if (ret) + goto err; + + ret =sunxi_mac_reset ((void *)priv->base, &sunxi_udelay,10000 ); +if (ret) { +netdev_err (ndev,"Initialize hardware error\n" ); + goto desc_err; + } + +sunxi_mac_init (priv->base, txmode, rxmode); +sunxi_set_umac (priv->base, ndev->dev_addr,0 ); + +if (!priv->is_suspend) { + ret =geth_dma_desc_init (ndev); +if (ret) { + ret = -EINVAL ; + goto desc_err; + } + } + +memset (priv->dma_tx,0 , dma_desc_tx *sizeof (struct dma_desc )); +memset (priv->dma_rx,0 , dma_desc_rx *sizeof (struct dma_desc )); + +desc_init_chain (priv->dma_rx, (unsigned long )priv->dma_rx_phy, dma_desc_rx); +desc_init_chain (priv->dma_tx, (unsigned long )priv->dma_tx_phy, dma_desc_tx); + + priv->rx_clean =0 ; + priv->rx_dirty =0 ; + priv->tx_clean =0 ; + priv->tx_dirty =0 ; +geth_rx_refill (ndev); + +/* Extra statistics */ +memset (&priv->xstats,0 ,sizeof (struct geth_extra_stats )); + +if (ndev->phydev) +phy_start (ndev->phydev); + +sunxi_start_rx (priv->base, (unsigned long )((struct dma_desc *) + priv->dma_rx_phy + priv->rx_dirty)); +sunxi_start_tx (priv->base, (unsigned long )((struct dma_desc *) + priv->dma_tx_phy + priv->tx_clean)); + +napi_enable (&priv->napi); +netif_start_queue (ndev); + +/* Enable the Rx/Tx */ +sunxi_mac_enable (priv->base); + +return 0 ; + +desc_err: +geth_phy_release (ndev); +err: +geth_clk_disable (priv); +if (priv->is_suspend) +napi_enable (&priv->napi); + +geth_power_off (priv); + +return ret; +} + +static int geth_stop (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); + +netif_stop_queue (ndev); +napi_disable (&priv->napi); + +netif_carrier_off (ndev); + +/* Release PHY resources */ +geth_phy_release (ndev); + +/* Disable Rx/Tx */ +sunxi_mac_disable (priv->base); + +geth_clk_disable (priv); +geth_power_off (priv); + +netif_tx_lock_bh (ndev); +/* Release the DMA TX/RX socket buffers */ +geth_free_rx_sk (priv); +geth_free_tx_sk (priv); +netif_tx_unlock_bh (ndev); + +/* Ensure that hareware have been stopped */ +if (!priv->is_suspend) +geth_free_dma_desc (priv); + +return 0 ; +} + +static void geth_tx_complete (struct geth_priv *priv) +{ +unsigned int entry =0 ; +struct sk_buff *skb =NULL ; +struct dma_desc *desc =NULL ; +int tx_stat; + +spin_lock (&priv->tx_lock); +while (circ_cnt (priv->tx_dirty, priv->tx_clean, dma_desc_tx) >0 ) { + entry = priv->tx_clean; + desc = priv->dma_tx + entry; + +/* Check if the descriptor is owned by the DMA. */ +if (desc_get_own (desc)) +break ; + +/* Verify tx error by looking at the last segment */ +if (desc_get_tx_ls (desc)) { + tx_stat =desc_get_tx_status (desc, (void *)(&priv->xstats)); + +if (likely (!tx_stat)) + priv->ndev->stats.tx_packets++; +else + priv->ndev->stats.tx_errors++; + } + +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc),DMA_TO_DEVICE ); + + skb = priv->tx_sk[entry]; + priv->tx_sk[entry] =NULL ; +desc_init (desc); + +/* Find next dirty desc */ + priv->tx_clean =circ_inc (entry, dma_desc_tx); + +if (unlikely (skb ==NULL )) +continue ; + +dev_kfree_skb (skb); + } + +if (unlikely (netif_queue_stopped (priv->ndev)) && +circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) > +TX_THRESH ) { +netif_wake_queue (priv->ndev); + } +spin_unlock (&priv->tx_lock); +} + +static netdev_tx_t geth_xmit (struct sk_buff *skb,struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int entry; +struct dma_desc *desc, *first; +unsigned int len, tmp_len =0 ; +int i, csum_insert; +int nfrags =skb_shinfo (skb)->nr_frags; +dma_addr_t paddr; + +spin_lock (&priv->tx_lock); +if (unlikely (circ_space (priv->tx_dirty, priv->tx_clean, + dma_desc_tx) < (nfrags +1 ))) { +if (!netif_queue_stopped (ndev)) { +netdev_err (ndev,"%s: BUG! Tx Ring full when queue awake\n" , __func__); +netif_stop_queue (ndev); + } +spin_unlock (&priv->tx_lock); + +return NETDEV_TX_BUSY ; + } + + csum_insert = (skb->ip_summed ==CHECKSUM_PARTIAL ); + entry = priv->tx_dirty; + first = priv->dma_tx + entry; + desc = priv->dma_tx + entry; + + len =skb_headlen (skb); + priv->tx_sk[entry] = skb; + +#ifdef PKT_DEBUG +printk ("======TX PKT DATA: ============\n" ); +/* dump the packet */ +print_hex_dump (KERN_DEBUG ,"skb->data: " ,DUMP_PREFIX_NONE , +16 ,1 , skb->data,64 , true); +#endif + +/* Every desc max size is 2K */ +while (len !=0 ) { + desc = priv->dma_tx + entry; + tmp_len = ((len >MAX_BUF_SZ ) ?MAX_BUF_SZ : len); + + paddr =dma_map_single (priv->dev, skb->data, tmp_len,DMA_TO_DEVICE ); +if (dma_mapping_error (priv->dev, paddr)) { +dev_kfree_skb (skb); +return -EIO ; + } +desc_buf_set (desc, paddr, tmp_len); +/* Don't set the first's own bit, here */ +if (first != desc) { + priv->tx_sk[entry] =NULL ; +desc_set_own (desc); + } + + entry =circ_inc (entry, dma_desc_tx); + len -= tmp_len; + } + +for (i =0 ; i < nfrags; i++) { +const skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; + + len =skb_frag_size (frag); + desc = priv->dma_tx + entry; + paddr =skb_frag_dma_map (priv->dev, frag,0 , len,DMA_TO_DEVICE ); +if (dma_mapping_error (priv->dev, paddr)) { +dev_kfree_skb (skb); +return -EIO ; + } + +desc_buf_set (desc, paddr, len); +desc_set_own (desc); + priv->tx_sk[entry] =NULL ; + entry =circ_inc (entry, dma_desc_tx); + } + + ndev->stats.tx_bytes += skb->len; + priv->tx_dirty = entry; +desc_tx_close (first, desc, csum_insert); + +desc_set_own (first); +spin_unlock (&priv->tx_lock); + +if (circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) <= + (MAX_SKB_FRAGS +1 )) { +netif_stop_queue (ndev); +if (circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) > +TX_THRESH ) +netif_wake_queue (ndev); + } + +#ifdef DEBUG +printk ("=======TX Descriptor DMA: 0x%08llx\n" , priv->dma_tx_phy); +printk ("Tx pointor: dirty: %d, clean: %d\n" , priv->tx_dirty, priv->tx_clean); +desc_print (priv->dma_tx, dma_desc_tx); +#endif +sunxi_tx_poll (priv->base); +geth_tx_complete (priv); + +return NETDEV_TX_OK ; +} + +static int geth_rx (struct geth_priv *priv,int limit) +{ +unsigned int rxcount =0 ; +unsigned int entry; +struct dma_desc *desc; +struct sk_buff *skb; +int status; +int frame_len; + +while (rxcount < limit) { + entry = priv->rx_dirty; + desc = priv->dma_rx + entry; + +if (desc_get_own (desc)) +break ; + + rxcount++; + priv->rx_dirty =circ_inc (priv->rx_dirty, dma_desc_rx); + +/* Get length & status from hardware */ + frame_len =desc_rx_frame_len (desc); + status =desc_get_rx_status (desc, (void *)(&priv->xstats)); + +netdev_dbg (priv->ndev,"Rx frame size %d, status: %d\n" , + frame_len, status); + + skb = priv->rx_sk[entry]; +if (unlikely (!skb)) { +netdev_err (priv->ndev,"Skb is null\n" ); + priv->ndev->stats.rx_dropped++; +break ; + } + +#ifdef PKT_DEBUG +printk ("======RX PKT DATA: ============\n" ); +/* dump the packet */ +print_hex_dump (KERN_DEBUG ,"skb->data: " ,DUMP_PREFIX_NONE , +16 ,1 , skb->data,64 , true); +#endif + +if (status == discard_frame) { +netdev_dbg (priv->ndev,"Get error pkt\n" ); + priv->ndev->stats.rx_errors++; +continue ; + } + +if (unlikely (status != llc_snap)) + frame_len -=ETH_FCS_LEN ; + + priv->rx_sk[entry] =NULL ; + +skb_put (skb, frame_len); +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc),DMA_FROM_DEVICE ); + + skb->protocol =eth_type_trans (skb, priv->ndev); + + skb->ip_summed =CHECKSUM_UNNECESSARY ; +napi_gro_receive (&priv->napi, skb); + + priv->ndev->stats.rx_packets++; + priv->ndev->stats.rx_bytes += frame_len; + } + +#ifdef DEBUG +if (rxcount >0 ) { +printk ("======RX Descriptor DMA: 0x%08llx=\n" , priv->dma_rx_phy); +printk ("RX pointor: dirty: %d, clean: %d\n" , priv->rx_dirty, priv->rx_clean); +desc_print (priv->dma_rx, dma_desc_rx); + } +#endif +geth_rx_refill (priv->ndev); + +return rxcount; +} + +static int geth_poll (struct napi_struct *napi,int budget) +{ + struct geth_priv *priv = container_of(napi, struct geth_priv, napi); +int work_done =0 ; + +geth_tx_complete (priv); + work_done =geth_rx (priv, budget); + +if (work_done < budget) { +napi_complete (napi); +sunxi_int_enable (priv->base); + } + +return work_done; +} + +static int geth_change_mtu (struct net_device *ndev,int new_mtu) +{ +int max_mtu; + +if (netif_running (ndev)) { +pr_err ("%s: must be stopped to change its MTU\n" , ndev->name); +return -EBUSY ; + } + + max_mtu =SKB_MAX_HEAD (NET_SKB_PAD +NET_IP_ALIGN ); + +if ((new_mtu <46 ) || (new_mtu > max_mtu)) { +pr_err ("%s: invalid MTU, max MTU is: %d\n" , ndev->name, max_mtu); +return -EINVAL ; + } + + ndev->mtu = new_mtu; +netdev_update_features (ndev); + +return 0 ; +} + +static netdev_features_t geth_fix_features (struct net_device *ndev, +netdev_features_t features) +{ +return features; +} + +static void geth_set_rx_mode (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int value =0 ; + +pr_debug ("%s: # mcasts %d, # unicast %d\n" , + __func__,netdev_mc_count (ndev),netdev_uc_count (ndev)); + +spin_lock (&priv->lock); +if (ndev->flags &IFF_PROMISC ) { + value =GETH_FRAME_FILTER_PR ; + }else if ((netdev_mc_count (ndev) >HASH_TABLE_SIZE ) || + (ndev->flags &IFF_ALLMULTI )) { + value =GETH_FRAME_FILTER_PM ;/* pass all multi */ +sunxi_hash_filter (priv->base, ~0UL , ~0UL ); + }else if (!netdev_mc_empty (ndev)) { +u32 mc_filter[2 ]; +struct netdev_hw_addr *ha; + +/* Hash filter for multicast */ + value =GETH_FRAME_FILTER_HMC ; + +memset (mc_filter,0 ,sizeof (mc_filter)); +netdev_for_each_mc_addr (ha, ndev) { +/* The upper 6 bits of the calculated CRC are used to +* index the contens of the hash table +*/ +int bit_nr =bitrev32 (~crc32_le (~0 , ha->addr,6 )) >>26 ; +/* The most significant bit determines the register to +* use (H/L) while the other 5 bits determine the bit +* within the register. +*/ + mc_filter[bit_nr >>5 ] |=1 << (bit_nr &31 ); + } +sunxi_hash_filter (priv->base, mc_filter[0 ], mc_filter[1 ]); + } + +/* Handle multiple unicast addresses (perfect filtering)*/ +if (netdev_uc_count (ndev) >16 ) { +/* Switch to promiscuous mode is more than 8 addrs are required */ + value |=GETH_FRAME_FILTER_PR ; + }else { +int reg =1 ; +struct netdev_hw_addr *ha; + +netdev_for_each_uc_addr (ha, ndev) { +sunxi_set_umac (priv->base, ha->addr, reg); + reg++; + } + } + +#ifdef FRAME_FILTER_DEBUG +/* Enable Receive all mode (to debug filtering_fail errors) */ + value |=GETH_FRAME_FILTER_RA ; +#endif +sunxi_set_filter (priv->base, value); +spin_unlock (&priv->lock); +} + +static void geth_tx_timeout (struct net_device *ndev,unsigned int txqueue) +{ +struct geth_priv *priv =netdev_priv (ndev); + +geth_tx_err (priv); +} + +static int geth_ioctl (struct net_device *ndev,struct ifreq *rq,int cmd) +{ +if (!netif_running (ndev)) +return -EINVAL ; + +if (!ndev->phydev) +return -EINVAL ; + +return phy_mii_ioctl (ndev->phydev, rq, cmd); +} + +/* Configuration changes (passed on by ifconfig) */ +static int geth_config (struct net_device *ndev,struct ifmap *map) +{ +if (ndev->flags &IFF_UP )/* can't act on a running interface */ +return -EBUSY ; + +/* Don't allow changing the I/O address */ +if (map->base_addr != ndev->base_addr) { +pr_warn ("%s: can't change I/O address\n" , ndev->name); +return -EOPNOTSUPP ; + } + +/* Don't allow changing the IRQ */ +if (map->irq != ndev->irq) { +pr_warn ("%s: can't change IRQ number %d\n" , ndev->name, ndev->irq); +return -EOPNOTSUPP ; + } + +return 0 ; +} + +static int geth_set_mac_address (struct net_device *ndev,void *p) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct sockaddr *addr = p; + +if (!is_valid_ether_addr (addr->sa_data)) +return -EADDRNOTAVAIL ; + +memcpy (ndev->dev_addr, addr->sa_data, ndev->addr_len); +sunxi_set_umac (priv->base, ndev->dev_addr,0 ); + +return 0 ; +} + +int geth_set_features (struct net_device *ndev,netdev_features_t features) +{ +struct geth_priv *priv =netdev_priv (ndev); + +if (features &NETIF_F_LOOPBACK &&netif_running (ndev)) +sunxi_mac_loopback (priv->base,1 ); +else +sunxi_mac_loopback (priv->base,0 ); + +return 0 ; +} + +#if IS_ENABLED (CONFIG_NET_POLL_CONTROLLER ) +/* Polling receive - used by NETCONSOLE and other diagnostic tools +* to allow network I/O with interrupts disabled. +*/ +static void geth_poll_controller (struct net_device *dev) +{ +disable_irq (dev->irq); +geth_interrupt (dev->irq, dev); +enable_irq (dev->irq); +} +#endif + +static const struct net_device_ops geth_netdev_ops = { + .ndo_init =NULL , + .ndo_open = geth_open, + .ndo_start_xmit = geth_xmit, + .ndo_stop = geth_stop, + .ndo_change_mtu = geth_change_mtu, + .ndo_fix_features = geth_fix_features, + .ndo_set_rx_mode = geth_set_rx_mode, + .ndo_tx_timeout = geth_tx_timeout, + .ndo_do_ioctl = geth_ioctl, + .ndo_set_config = geth_config, +#if IS_ENABLED(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = geth_poll_controller, +#endif + .ndo_set_mac_address = geth_set_mac_address, + .ndo_set_features = geth_set_features, +}; + +static int geth_check_if_running (struct net_device *ndev) +{ +if (!netif_running (ndev)) +return -EBUSY ; +return 0 ; +} + +static int geth_get_sset_count (struct net_device *netdev,int sset) +{ +int len; + +switch (sset) { +case ETH_SS_STATS : + len =0 ; +return len; +default : +return -EOPNOTSUPP ; + } +} + +/*static int geth_ethtool_getsettings(struct net_device *ndev, +struct ethtool_cmd *cmd) +{ +struct geth_priv *priv = netdev_priv(ndev); +struct phy_device *phy = ndev->phydev; +int rc; + +if (phy == NULL) { +netdev_err(ndev, "%s: %s: PHY is not registered\n", +__func__, ndev->name); +return -ENODEV; +} + +if (!netif_running(ndev)) { +pr_err("%s: interface is disabled: we cannot track " +"link speed / duplex setting\n", ndev->name); +return -EBUSY; +} + +cmd->transceiver = XCVR_INTERNAL; +spin_lock_irq(&priv->lock); +//rc = phy_ethtool_gset(phy, cmd); +spin_unlock_irq(&priv->lock); + +return rc; +} + +static int geth_ethtool_setsettings(struct net_device *ndev, +struct ethtool_cmd *cmd) +{ +struct geth_priv *priv = netdev_priv(ndev); +struct phy_device *phy = ndev->phydev; +int rc; + +spin_lock(&priv->lock); +rc = phy_ethtool_sset(phy, cmd); +spin_unlock(&priv->lock); + +return rc; +}*/ + +static void geth_ethtool_getdrvinfo (struct net_device *ndev, +struct ethtool_drvinfo *info) +{ +strlcpy (info->driver,"sunxi_geth" ,sizeof (info->driver)); + +#define DRV_MODULE_VERSION "SUNXI Gbgit driver V1.1" + +strcpy (info->version,DRV_MODULE_VERSION ); + info->fw_version[0 ] ='\0' ; +} + +static const struct ethtool_ops geth_ethtool_ops = { + .begin = geth_check_if_running, +//.get_settings = geth_ethtool_getsettings, +//.set_settings = geth_ethtool_setsettings, + .get_link = ethtool_op_get_link, + .get_pauseparam =NULL , + .set_pauseparam =NULL , + .get_ethtool_stats =NULL , + .get_strings =NULL , + .get_wol =NULL , + .set_wol =NULL , + .get_sset_count = geth_get_sset_count, + .get_drvinfo = geth_ethtool_getdrvinfo, +}; + +/* config hardware resource */ +static int geth_hw_init (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); +struct device_node *np = pdev->dev.of_node; +int ret =0 ; +struct resource *res; +u32 value; +// struct gpio_config cfg; +// const char *gmac_power; +// char power[20]; +// int i; + +#if 1 + priv->phy_ext =EXT_PHY ; +#else + priv->phy_ext =INT_PHY ; +#endif + +/* config memery resource */ + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (unlikely (!res)) { +pr_err ("%s: ERROR: get gmac memory failed" , __func__); +return -ENODEV ; + } + + priv->base =devm_ioremap_resource (&pdev->dev, res); +if (!priv->base) { +pr_err ("%s: ERROR: gmac memory mapping failed" , __func__); +return -ENOMEM ; + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (unlikely (!res)) { +pr_err ("%s: ERROR: get phy memory failed" , __func__); + ret = -ENODEV ; + goto mem_err; + } + + priv->base_phy =devm_ioremap_resource (&pdev->dev, res); +if (unlikely (!priv->base_phy)) { +pr_err ("%s: ERROR: phy memory mapping failed" , __func__); + ret = -ENOMEM ; + goto mem_err; + } + +/* config IRQ */ + ndev->irq =platform_get_irq_byname (pdev,"gmacirq" ); +if (ndev->irq == -ENXIO ) { +pr_err ("%s: ERROR: MAC IRQ not found\n" , __func__); + ret = -ENXIO ; + goto irq_err; + } + + ret =request_irq (ndev->irq, geth_interrupt,IRQF_SHARED ,dev_name (&pdev->dev), ndev); +if (unlikely (ret <0 )) { +pr_err ("Could not request irq %d, error: %d\n" , ndev->irq, ret); + goto irq_err; + } + +/* get gmac rst handle */ +/* +priv->reset = devm_reset_control_get(&pdev->dev, NULL); +if (IS_ERR(priv->reset)) { +pr_err("%s: Get gmac reset control failed!\n", __func__); +return PTR_ERR(priv->reset); +} +*/ +/* config clock */ +/* +priv->geth_clk = of_clk_get_by_name(np, "gmac"); +if (unlikely(!priv->geth_clk || IS_ERR(priv->geth_clk))) { +pr_err("Get gmac clock failed!\n"); +ret = -EINVAL; +goto clk_err; +} + +if (INT_PHY == priv->phy_ext) { +priv->ephy_clk = of_clk_get_by_name(np, "ephy"); +if (unlikely(IS_ERR_OR_NULL(priv->ephy_clk))) { +pr_err("Get ephy clock failed!\n"); +ret = -EINVAL; +goto clk_err; +} +} else { +if (!of_property_read_u32(np, "use-ephy25m", &(priv->use_ephy_clk)) +&& priv->use_ephy_clk) { +priv->ephy_clk = of_clk_get_by_name(np, "ephy"); +if (unlikely(IS_ERR_OR_NULL(priv->ephy_clk))) { +pr_err("Get ephy clk failed!\n"); +ret = -EINVAL; +goto clk_err; +} +} +} +*/ +/* config power regulator */ +/* +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +snprintf(power, 15, "gmac-power%d", i); +ret = of_property_read_string(np, power, &gmac_power); +if (ret) { +priv->gmac_power[i] = NULL; +pr_info("gmac-power%d: NULL\n", i); +continue; +} +priv->gmac_power[i] = regulator_get(NULL, gmac_power); +if (IS_ERR(priv->gmac_power[i])) { +pr_err("gmac-power%d get error!\n", i); +ret = -EINVAL; +goto clk_err; +} +} +} +*/ +/* config other parameters */ +of_get_phy_mode (np, &(priv->phy_interface)); +if (priv->phy_interface !=PHY_INTERFACE_MODE_MII && + priv->phy_interface !=PHY_INTERFACE_MODE_RGMII && + priv->phy_interface !=PHY_INTERFACE_MODE_RMII ) { +pr_err ("Not support phy type!\n" ); + priv->phy_interface =PHY_INTERFACE_MODE_MII ; + } + +if (!of_property_read_u32 (np,"tx-delay" , &value)) + priv->tx_delay = value; + +if (!of_property_read_u32 (np,"rx-delay" , &value)) + priv->rx_delay = value; + +/* config pinctrl */ +/* +if (EXT_PHY == priv->phy_ext) { +priv->phyrst = of_get_named_gpio_flags(np, "phy-rst", 0, (enum of_gpio_flags *)&cfg); +priv->rst_active_low = (cfg.data == OF_GPIO_ACTIVE_LOW) ? 1 : 0; + +if (gpio_is_valid(priv->phyrst)) { +if (gpio_request(priv->phyrst, "phy-rst") < 0) { +pr_err("gmac gpio request fail!\n"); +ret = -EINVAL; +goto pin_err; +} +} + +priv->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); +if (IS_ERR_OR_NULL(priv->pinctrl)) { +pr_err("gmac pinctrl error!\n"); +priv->pinctrl = NULL; +ret = -EINVAL; +goto pin_err; +} +} +*/ +return 0 ; + +//pin_err: +/* +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_put(priv->gmac_power[i]); +} +} +*/ +//clk_err: +// free_irq(ndev->irq, ndev); +irq_err: +devm_iounmap (&pdev->dev, priv->base_phy); +mem_err: +devm_iounmap (&pdev->dev, priv->base); + +return ret; +} + +static void geth_hw_release (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); + +devm_iounmap (&pdev->dev, (priv->base_phy)); +devm_iounmap (&pdev->dev, priv->base); +free_irq (ndev->irq, ndev); +/* +if (priv->geth_clk) +clk_put(priv->geth_clk); + +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_put(priv->gmac_power[i]); +} + +if (!IS_ERR_OR_NULL(priv->pinctrl)) +devm_pinctrl_put(priv->pinctrl); + +if (gpio_is_valid(priv->phyrst)) +gpio_free(priv->phyrst); +} + +if (!IS_ERR_OR_NULL(priv->ephy_clk)) +clk_put(priv->ephy_clk); +*/ +} + +/** +* geth_probe +* @pdev: platform device pointer +* Description: the driver is initialized through platform_device. +*/ +static int geth_probe (struct platform_device *pdev) +{ +int ret =0 ; +struct net_device *ndev =NULL ; +struct geth_priv *priv; + +pr_info ("sunxi gmac driver's version: %s\n" ,SUNXI_GMAC_VERSION ); + +#if IS_ENABLED (CONFIG_OF ) + pdev->dev.dma_mask = &geth_dma_mask; + pdev->dev.coherent_dma_mask =DMA_BIT_MASK (32 ); +#endif + + ndev =alloc_etherdev (sizeof (struct geth_priv )); +if (!ndev) { +dev_err (&pdev->dev,"could not allocate device.\n" ); +return -ENOMEM ; + } +SET_NETDEV_DEV (ndev, &pdev->dev); + + priv =netdev_priv (ndev); +platform_set_drvdata (pdev, ndev); + +/* Must set private data to pdev, before call it */ + ret =geth_hw_init (pdev); +if (0 != ret) { +pr_err ("geth_hw_init fail!\n" ); + goto hw_err; + } + +/* setup the netdevice, fill the field of netdevice */ +ether_setup (ndev); + ndev->netdev_ops = &geth_netdev_ops; +netdev_set_default_ethtool_ops (ndev, &geth_ethtool_ops); + ndev->base_addr = (unsigned long )priv->base; + + priv->ndev = ndev; + priv->dev = &pdev->dev; + +/* TODO: support the VLAN frames */ + ndev->hw_features =NETIF_F_SG |NETIF_F_HIGHDMA |NETIF_F_IP_CSUM | +NETIF_F_IPV6_CSUM |NETIF_F_RXCSUM ; + + ndev->features |= ndev->hw_features; + ndev->hw_features |=NETIF_F_LOOPBACK ; + ndev->priv_flags |=IFF_UNICAST_FLT ; + + ndev->watchdog_timeo =msecs_to_jiffies (watchdog); + +netif_napi_add (ndev, &priv->napi, geth_poll,BUDGET ); + +spin_lock_init (&priv->lock); +spin_lock_init (&priv->tx_lock); + +/* The last val is mdc clock ratio */ +sunxi_geth_register ((void *)ndev->base_addr,HW_VERSION ,0x03 ); + + ret =register_netdev (ndev); +if (ret) { +netif_napi_del (&priv->napi); +pr_err ("Error: Register %s failed\n" , ndev->name); + goto reg_err; + } + +/* Before open the device, the mac address should be set */ +geth_check_addr (ndev, mac_str); + +#ifdef CONFIG_GETH_ATTRS +geth_create_attrs (ndev); +#endif +device_create_file (&pdev->dev, &dev_attr_gphy_test); +device_create_file (&pdev->dev, &dev_attr_mii_reg); +device_create_file (&pdev->dev, &dev_attr_loopback_test); +device_create_file (&pdev->dev, &dev_attr_extra_tx_stats); +device_create_file (&pdev->dev, &dev_attr_extra_rx_stats); + +device_enable_async_suspend (&pdev->dev); + +#if IS_ENABLED (CONFIG_PM ) +INIT_WORK (&priv->eth_work, geth_resume_work); +#endif + +return 0 ; + +reg_err: +geth_hw_release (pdev); +hw_err: +platform_set_drvdata (pdev,NULL ); +free_netdev (ndev); + +return ret; +} + +static int geth_remove (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); + +device_remove_file (&pdev->dev, &dev_attr_gphy_test); +device_remove_file (&pdev->dev, &dev_attr_mii_reg); +device_remove_file (&pdev->dev, &dev_attr_loopback_test); +device_remove_file (&pdev->dev, &dev_attr_extra_tx_stats); +device_remove_file (&pdev->dev, &dev_attr_extra_rx_stats); + +netif_napi_del (&priv->napi); +unregister_netdev (ndev); +geth_hw_release (pdev); +platform_set_drvdata (pdev,NULL ); +free_netdev (ndev); + +return 0 ; +} + +static const struct of_device_id geth_of_match[] = { + {.compatible ="allwinner,sunxi-gmac" ,}, + {}, +}; +MODULE_DEVICE_TABLE (of, geth_of_match); + +static struct platform_driver geth_driver = { + .probe = geth_probe, + .remove = geth_remove, + .driver = { + .name ="sunxi-gmac" , + .owner =THIS_MODULE , + .pm = &geth_pm_ops, + .of_match_table = geth_of_match, + }, +}; +module_platform_driver (geth_driver); + +#ifdef MODULE +static int __init set_mac_addr (char *str) +{ +char *p = str; + +if (str &&strlen (str)) +memcpy (mac_str, p,18 ); + +return 0 ; +} +__setup ("mac_addr=" , set_mac_addr); +#endif + +MODULE_DESCRIPTION ("Allwinner Gigabit Ethernet driver" ); +MODULE_AUTHOR ("fuzhaoke <[email protected]>" ); +MODULE_LICENSE ("Dual BSD/GPL" );drivers/net/ethernet/allwinnertmp/sunxi-gmac.h new file +258
-0@@ -0,0 +1,258 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac.h +* Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Re: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
,
Quoted 20 lines · Andre Przywara
On Sun, 6 Jun 2021 09:04:09 +0000
[email protected] wrote:Hi,
Quoted 4 lines
From: liush <[email protected]>
This is a temporary driver, only guaranteed to work on allwinner D1. In order to ensure the developer's demand for network usage.
That looks like some Allwinner BSP driver, please don't endorse code of this quality (just look at all that commented code and the attempt for compile-time configuration).
Quoted 5 lines
It only could work at 1Gps mode.
The correct gmac driver should follow (I guess)
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
Quoted 6 lines
Quoted 2 lines
If anyone is familiar with it and can help porting, I would be very grateful.
Have you tried compiling and using that driver? Ideally it should just work, Linux drivers are meant to be portable, by design. And the driver is already enabled by
COMPILE_TEST.
It still needs some work with dwmac-sun8i.c glue layer, eg:
tx/rx-delay setting, clk & pinmux drivers.
The patch is just to help people using D1 with GMAC temporarily with network function.
Quoted 3 lines
But I guess you need some extra care to make the non-coherent DMA work? I haven't looked in detail, but are those new CMOs hooked into the generic DMA framework?
Yes, we have the simliar principle with arm & csky for non-coherent:
- Using PTE attributes setting Using PTE attributes to support_PAGE_IOREMAP & _PAGE_WRITECOMBINE
- Using CMO instructions deal SYNC_DMA_FOR_CPU/DEVICE.
Quoted 3,346 lines
Cheers,
AndreQuoted 3,342 lines
Signed-off-by Liu Shaohua <[email protected]>Tested-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc Maxime Ripard <[email protected]>Cc Corentin Labbe <[email protected]>Cc Samuel Holland <[email protected]>Cc Icenowy Zheng <[email protected]>Cc LABBE Corentin <[email protected]>Cc Michael Walle <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Signed-off-by Guo Ren <[email protected]>--- .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 2 +- arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 16 + drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- 10 files changed, 3232 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.harch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/init root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23"; stdout-path = &serial0; };arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +16
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030 0x00 0x04>; + interrupts-extended = <&plic 0x3e 0x04>; + interrupt-names = "gmacirq"; + device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + }; }; };drivers/net/ethernet/Kconfig +1
-0@@ -18,6 +18,7 @@ config MDIO config SUNGEM_PHY tristate +source "drivers/net/ethernet/allwinnertmp/Kconfig" source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/actions/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig"drivers/net/ethernet/Makefile +1
-0@@ -3,6 +3,7 @@ # Makefile for the Linux network Ethernet device drivers. # +obj-y += allwinnertmp/ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ACTIONS) += actions/drivers/net/ethernet/allwinnertmp/Kconfig new file +17
-0@@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Allwinner device configuration +# + +config SUNXI_GMAC + tristate "Allwinner GMAC support" + default y + depends on OF + select CRC32 + select MII + select PHYLIB + help + Support for Allwinner Gigabit ethernet driver. + + To compile this driver as a module, choose M here. The module + will be called sunxi-gmac.drivers/net/ethernet/allwinnertmp/Makefile new file +7
-0@@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Allwinner device drivers. +# + +obj-$(CONFIG_SUNXI_GMAC) += sunxi_gmac.o +sunxi_gmac-objs := sunxi-gmac.o sunxi-gmac-ops.odrivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c new file +690
-0@@ -0,0 +1,690 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c +* +* Copyright © 2016-2018, fuzhaoke +* Author: fuzhaoke <[email protected]> +* +* This file is provided under a dual BSD/GPL license. When using or +* redistributing this file, you may do so under either license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#include <linux/kernel.h> +#include <linux/ctype.h> +#include <linux/printk.h> +#include <linux/io.h> +#include "sunxi-gmac.h" + +/****************************************************************************** +* sun8iw6 operations +*****************************************************************************/ +#define GETH_BASIC_CTL0 0x00 +#define GETH_BASIC_CTL1 0x04 +#define GETH_INT_STA 0x08 +#define GETH_INT_EN 0x0C +#define GETH_TX_CTL0 0x10 +#define GETH_TX_CTL1 0x14 +#define GETH_TX_FLOW_CTL 0x1C +#define GETH_TX_DESC_LIST 0x20 +#define GETH_RX_CTL0 0x24 +#define GETH_RX_CTL1 0x28 +#define GETH_RX_DESC_LIST 0x34 +#define GETH_RX_FRM_FLT 0x38 +#define GETH_RX_HASH0 0x40 +#define GETH_RX_HASH1 0x44 +#define GETH_MDIO_ADDR 0x48 +#define GETH_MDIO_DATA 0x4C +#define GETH_ADDR_HI (reg) (0x50 + ((reg) << 3)) +#define GETH_ADDR_LO (reg) (0x54 + ((reg) << 3)) +#define GETH_TX_DMA_STA 0xB0 +#define GETH_TX_CUR_DESC 0xB4 +#define GETH_TX_CUR_BUF 0xB8 +#define GETH_RX_DMA_STA 0xC0 +#define GETH_RX_CUR_DESC 0xC4 +#define GETH_RX_CUR_BUF 0xC8 +#define GETH_RGMII_STA 0xD0 + +#define RGMII_IRQ 0x00000001 + +#define CTL0_LM 0x02 +#define CTL0_DM 0x01 +#define CTL0_SPEED 0x04 + +#define BURST_LEN 0x3F000000 +#define RX_TX_PRI 0x02 +#define SOFT_RST 0x01 + +#define TX_FLUSH 0x01 +#define TX_MD 0x02 +#define TX_NEXT_FRM 0x04 +#define TX_TH 0x0700 + +#define RX_FLUSH 0x01 +#define RX_MD 0x02 +#define RX_RUNT_FRM 0x04 +#define RX_ERR_FRM 0x08 +#define RX_TH 0x0030 + +#define TX_INT 0x00001 +#define TX_STOP_INT 0x00002 +#define TX_UA_INT 0x00004 +#define TX_TOUT_INT 0x00008 +#define TX_UNF_INT 0x00010 +#define TX_EARLY_INT 0x00020 +#define RX_INT 0x00100 +#define RX_UA_INT 0x00200 +#define RX_STOP_INT 0x00400 +#define RX_TOUT_INT 0x00800 +#define RX_OVF_INT 0x01000 +#define RX_EARLY_INT 0x02000 +#define LINK_STA_INT 0x10000 + +#define DISCARD_FRAME -1 +#define GOOD_FRAME 0 +#define CSUM_NONE 2 +#define LLC_SNAP 4 + +#define SF_DMA_MODE 1 + +/* Flow Control defines */ +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + +#define HASH_TABLE_SIZE 64 +#define PAUSE_TIME 0x200 +#define GMAC_MAX_UNICAST_ADDRESSES 8 + +/* PHY address */ +#define PHY_ADDR 0x01 +#define PHY_DM 0x0010 +#define PHY_AUTO_NEG 0x0020 +#define PHY_POWERDOWN 0x0080 +#define PHY_NEG_EN 0x1000 + +#define MII_BUSY 0x00000001 +#define MII_WRITE 0x00000002 +#define MII_PHY_MASK 0x0000FFC0 +#define MII_CR_MASK 0x0000001C +#define MII_CLK 0x00000008 +/* bits 4 3 2 | AHB1 Clock | MDC Clock +* ------------------------------------------------------- +* 0 0 0 | 60 ~ 100 MHz | div-42 +* 0 0 1 | 100 ~ 150 MHz | div-62 +* 0 1 0 | 20 ~ 35 MHz | div-16 +* 0 1 1 | 35 ~ 60 MHz | div-26 +* 1 0 0 | 150 ~ 250 MHz | div-102 +* 1 0 1 | 250 ~ 300 MHz | div-124 +* 1 1 x | Reserved | +*/ + +enum csum_insertion { + cic_dis =0 ,/* Checksum Insertion Control */ + cic_ip =1 ,/* Only IP header */ + cic_no_pse =2 ,/* IP header but not pseudoheader */ + cic_full =3 ,/* IP header and pseudoheader */ +}; + +struct gethdev { +void *iobase; +unsigned int ver; +unsigned int mdc_div; +}; + +static struct gethdev hwdev; + +/*************************************************************************** +* External interface +**************************************************************************/ +/* Set a ring desc buffer */ +void desc_init_chain (struct dma_desc *desc,unsigned long addr,unsigned int size) +{ +/* In chained mode the desc3 points to the next element in the ring. +* The latest element has to point to the head. +*/ +int i; +struct dma_desc *p = desc; +unsigned long dma_phy = addr; + +for (i =0 ; i < (size -1 ); i++) { + dma_phy +=sizeof (struct dma_desc ); + p->desc3 = (unsigned int )dma_phy; +/* Chain mode */ + p->desc1.all |= (1 <<24 ); + p++; + } + p->desc1.all |= (1 <<24 ); + p->desc3 = (unsigned int )addr; +} + +int sunxi_mdio_read (void *iobase,int phyaddr,int phyreg) +{ +unsigned int value =0 ; + +/* Mask the MDC_DIV_RATIO */ + value |= ((hwdev.mdc_div &0x07 ) <<20 ); + value |= (((phyaddr <<12 ) & (0x0001F000 )) | + ((phyreg <<4 ) & (0x000007F0 )) | +MII_BUSY ); + +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +writel (value, iobase +GETH_MDIO_ADDR ); +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +return (int )readl (iobase +GETH_MDIO_DATA ); +} + +int sunxi_mdio_write (void *iobase,int phyaddr,int phyreg,unsigned short data) +{ +unsigned int value; + + value = ((0x07 <<20 ) &readl (iobase +GETH_MDIO_ADDR )) | + (hwdev.mdc_div <<20 ); + value |= (((phyaddr <<12 ) & (0x0001F000 )) | + ((phyreg <<4 ) & (0x000007F0 ))) | +MII_WRITE |MII_BUSY ; + +/* Wait until any existing MII operation is complete */ +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +/* Set the MII address register to write */ +writel (data, iobase +GETH_MDIO_DATA ); +writel (value, iobase +GETH_MDIO_ADDR ); + +/* Wait until any existing MII operation is complete */ +while (((readl (iobase +GETH_MDIO_ADDR )) &MII_BUSY ) ==1 ) + ; + +return 0 ; +} + +int sunxi_mdio_reset (void *iobase) +{ +writel ((4 <<2 ), iobase +GETH_MDIO_ADDR ); +return 0 ; +} + +void sunxi_set_link_mode (void *iobase,int duplex,int speed) +{ +unsigned int ctrl =readl (iobase +GETH_BASIC_CTL0 ); + +if (!duplex) + ctrl &= ~CTL0_DM ; +else + ctrl |=CTL0_DM ; + +switch (speed) { +case 1000 : + ctrl &= ~0x0C ; +break ; +case 100 : +case 10 : +default : + ctrl |=0x08 ; +if (speed ==100 ) + ctrl |=0x04 ; +else + ctrl &= ~0x04 ; +break ; + } + +writel (ctrl, iobase +GETH_BASIC_CTL0 ); +} + +void sunxi_mac_loopback (void *iobase,int enable) +{ +int reg; + + reg =readl (iobase +GETH_BASIC_CTL0 ); +if (enable) + reg |=0x02 ; +else + reg &= ~0x02 ; +writel (reg, iobase +GETH_BASIC_CTL0 ); +} + +void sunxi_flow_ctrl (void *iobase,int duplex,int fc,int pause) +{ +unsigned int flow =0 ; + +if (fc &FLOW_RX ) { + flow =readl (iobase +GETH_RX_CTL0 ); + flow |=0x10000 ; +writel (flow, iobase +GETH_RX_CTL0 ); + } + +if (fc &FLOW_TX ) { + flow =readl (iobase +GETH_TX_FLOW_CTL ); + flow |=0x00001 ; +writel (flow, iobase +GETH_TX_FLOW_CTL ); + } + +if (duplex) { + flow =readl (iobase +GETH_TX_FLOW_CTL ); + flow |= (pause <<4 ); +writel (flow, iobase +GETH_TX_FLOW_CTL ); + } +} + +int sunxi_int_status (void *iobase,struct geth_extra_stats *x) +{ +int ret =0 ; +/* read the status register (CSR5) */ +unsigned int intr_status; + + intr_status =readl (iobase +GETH_RGMII_STA ); +if (intr_status &RGMII_IRQ ) +readl (iobase +GETH_RGMII_STA ); + + intr_status =readl (iobase +GETH_INT_STA ); + +/* ABNORMAL interrupts */ +if (intr_status &TX_UNF_INT ) { + ret = tx_hard_error_bump_tc; + x->tx_undeflow_irq++; + } +if (intr_status &TX_TOUT_INT ) { + x->tx_jabber_irq++; + } +if (intr_status &RX_OVF_INT ) { + x->rx_overflow_irq++; + } +if (intr_status &RX_UA_INT ) { + x->rx_buf_unav_irq++; + } +if (intr_status &RX_STOP_INT ) { + x->rx_process_stopped_irq++; + } +if (intr_status &RX_TOUT_INT ) { + x->rx_watchdog_irq++; + } +if (intr_status &TX_EARLY_INT ) { + x->tx_early_irq++; + } +if (intr_status &TX_STOP_INT ) { + x->tx_process_stopped_irq++; + ret = tx_hard_error; + } + +/* TX/RX NORMAL interrupts */ +if (intr_status & (TX_INT |RX_INT |RX_EARLY_INT |TX_UA_INT )) { + x->normal_irq_n++; +if (intr_status & (TX_INT |RX_INT )) + ret = handle_tx_rx; + } +/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ +writel (intr_status &0x3FFF , iobase +GETH_INT_STA ); + +return ret; +} + +void sunxi_start_rx (void *iobase,unsigned long rxbase) +{ +unsigned int value; + +/* Write the base address of Rx descriptor lists into registers */ +writel (rxbase, iobase +GETH_RX_DESC_LIST ); + + value =readl (iobase +GETH_RX_CTL1 ); + value |=0x40000000 ; +writel (value, iobase +GETH_RX_CTL1 ); +} + +void sunxi_stop_rx (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_RX_CTL1 ); + value &= ~0x40000000 ; +writel (value, iobase +GETH_RX_CTL1 ); +} + +void sunxi_start_tx (void *iobase,unsigned long txbase) +{ +unsigned int value; + +/* Write the base address of Tx descriptor lists into registers */ +writel (txbase, iobase +GETH_TX_DESC_LIST ); + + value =readl (iobase +GETH_TX_CTL1 ); + value |=0x40000000 ; +writel (value, iobase +GETH_TX_CTL1 ); +} + +void sunxi_stop_tx (void *iobase) +{ +unsigned int value =readl (iobase +GETH_TX_CTL1 ); + + value &= ~0x40000000 ; +writel (value, iobase +GETH_TX_CTL1 ); +} + +static int sunxi_dma_init (void *iobase) +{ +unsigned int value; + +/* Burst should be 8 */ + value = (8 <<24 ); + +#ifdef CONFIG_GMAC_DA + value |=RX_TX_PRI ;/* Rx has priority over tx */ +#endif +writel (value, iobase +GETH_BASIC_CTL1 ); + +/* Mask interrupts by writing to CSR7 */ +writel (RX_INT |TX_UNF_INT , iobase +GETH_INT_EN ); + +return 0 ; +} + +int sunxi_mac_init (void *iobase,int txmode,int rxmode) +{ +unsigned int value; + +sunxi_dma_init (iobase); + +/* Initialize the core component */ + value =readl (iobase +GETH_TX_CTL0 ); + value |= (1 <<30 );/* Jabber Disable */ +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value |= (1 <<27 );/* Enable CRC & IPv4 Header Checksum */ + value |= (1 <<28 );/* Automatic Pad/CRC Stripping */ + value |= (1 <<29 );/* Jumbo Frame Enable */ +writel (value, iobase +GETH_RX_CTL0 ); + +writel ((hwdev.mdc_div <<20 ), iobase +GETH_MDIO_ADDR );/* MDC_DIV_RATIO */ + +/* Set the Rx&Tx mode */ + value =readl (iobase +GETH_TX_CTL1 ); +if (txmode ==SF_DMA_MODE ) { +/* Transmit COE type 2 cannot be done in cut-through mode. */ + value |=TX_MD ; +/* Operating on second frame increase the performance +* especially when transmit store-and-forward is used. +*/ + value |=TX_NEXT_FRM ; + }else { + value &= ~TX_MD ; + value &= ~TX_TH ; +/* Set the transmit threshold */ +if (txmode <=64 ) + value |=0x00000000 ; +else if (txmode <=128 ) + value |=0x00000100 ; +else if (txmode <=192 ) + value |=0x00000200 ; +else + value |=0x00000300 ; + } +writel (value, iobase +GETH_TX_CTL1 ); + + value =readl (iobase +GETH_RX_CTL1 ); +if (rxmode ==SF_DMA_MODE ) { + value |=RX_MD ; + }else { + value &= ~RX_MD ; + value &= ~RX_TH ; +if (rxmode <=32 ) + value |=0x10 ; +else if (rxmode <=64 ) + value |=0x00 ; +else if (rxmode <=96 ) + value |=0x20 ; +else + value |=0x30 ; + } + +/* Forward frames with error and undersized good frame. */ + value |= (RX_ERR_FRM |RX_RUNT_FRM ); + +writel (value, iobase +GETH_RX_CTL1 ); + +return 0 ; +} + +void sunxi_hash_filter (void *iobase,unsigned long low,unsigned long high) +{ +writel (high, iobase +GETH_RX_HASH0 ); +writel (low, iobase +GETH_RX_HASH1 ); +} + +void sunxi_set_filter (void *iobase,unsigned long flags) +{ +int tmp_flags =0 ; + + tmp_flags |= ((flags >>31 ) | + ((flags >>9 ) &0x00000002 ) | + ((flags <<1 ) &0x00000010 ) | + ((flags >>3 ) &0x00000060 ) | + ((flags <<7 ) &0x00000300 ) | + ((flags <<6 ) &0x00003000 ) | + ((flags <<12 ) &0x00030000 ) | + (flags <<31 )); + +writel (tmp_flags, iobase +GETH_RX_FRM_FLT ); +} + +void sunxi_set_umac (void *iobase,unsigned char *addr,int index) +{ +unsigned long data; + + data = (addr[5 ] <<8 ) | addr[4 ]; +writel (data, iobase +GETH_ADDR_HI (index)); + data = (addr[3 ] <<24 ) | (addr[2 ] <<16 ) | (addr[1 ] <<8 ) | addr[0 ]; +writel (data, iobase +GETH_ADDR_LO (index)); +} + +void sunxi_mac_enable (void *iobase) +{ +unsigned long value; + + value =readl (iobase +GETH_TX_CTL0 ); + value |= (1 <<31 ); +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value |= (1 <<31 ); +writel (value, iobase +GETH_RX_CTL0 ); +} + +void sunxi_mac_disable (void *iobase) +{ +unsigned long value; + + value =readl (iobase +GETH_TX_CTL0 ); + value &= ~(1 <<31 ); +writel (value, iobase +GETH_TX_CTL0 ); + + value =readl (iobase +GETH_RX_CTL0 ); + value &= ~(1 <<31 ); +writel (value, iobase +GETH_RX_CTL0 ); +} + +void sunxi_tx_poll (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_TX_CTL1 ); +writel (value |0x80000000 , iobase +GETH_TX_CTL1 ); +} + +void sunxi_rx_poll (void *iobase) +{ +unsigned int value; + + value =readl (iobase +GETH_RX_CTL1 ); +writel (value |0x80000000 , iobase +GETH_RX_CTL1 ); +} + +void sunxi_int_enable (void *iobase) +{ +writel (RX_INT |TX_UNF_INT , iobase +GETH_INT_EN ); +} + +void sunxi_int_disable (void *iobase) +{ +writel (0 , iobase +GETH_INT_EN ); +} + +void desc_buf_set (struct dma_desc *desc,unsigned long paddr,int size) +{ + desc->desc1.all &= (~((1 <<11 ) -1 )); + desc->desc1.all |= (size & ((1 <<11 ) -1 )); + desc->desc2 = paddr; +} + +void desc_set_own (struct dma_desc *desc) +{ + desc->desc0.all |=0x80000000 ; +} + +void desc_tx_close (struct dma_desc *first,struct dma_desc *end,int csum_insert) +{ +struct dma_desc *desc = first; + + first->desc1.tx.first_sg =1 ; + end->desc1.tx.last_seg =1 ; + end->desc1.tx.interrupt =1 ; + +if (csum_insert) +do { + desc->desc1.tx.cic =3 ; + desc++; + }while (desc <= end); +} + +void desc_init (struct dma_desc *desc) +{ + desc->desc1.all =0 ; + desc->desc2 =0 ; + + desc->desc1.all |= (1 <<24 ); +} + +int desc_get_tx_status (struct dma_desc *desc,struct geth_extra_stats *x) +{ +int ret =0 ; + +if (desc->desc0.tx.under_err) { + x->tx_underflow++; + ret =-1 ; + } +if (desc->desc0.tx.no_carr) { + x->tx_carrier++; + ret =-1 ; + } +if (desc->desc0.tx.loss_carr) { + x->tx_losscarrier++; + ret =-1 ; + } + +#if 0 +if ((desc->desc0.tx.ex_deferral) || + (desc->desc0.tx.ex_coll) || + (desc->desc0.tx.late_coll)) + stats->collisions += desc->desc0.tx.coll_cnt; +#endif + +if (desc->desc0.tx.deferred) + x->tx_deferred++; + +return ret; +} + +int desc_buf_get_len (struct dma_desc *desc) +{ +return (desc->desc1.all & ((1 <<11 ) -1 )); +} + +int desc_buf_get_addr (struct dma_desc *desc) +{ +return desc->desc2; +} + +int desc_rx_frame_len (struct dma_desc *desc) +{ +return desc->desc0.rx.frm_len; +} + +int desc_get_rx_status (struct dma_desc *desc,struct geth_extra_stats *x) +{ +int ret = good_frame; + +if (desc->desc0.rx.last_desc ==0 ) { +return discard_frame; + } + +if (desc->desc0.rx.err_sum) { +if (desc->desc0.rx.desc_err) + x->rx_desc++; + +if (desc->desc0.rx.sou_filter) + x->sa_filter_fail++; + +if (desc->desc0.rx.over_err) + x->overflow_error++; + +if (desc->desc0.rx.ipch_err) + x->ipc_csum_error++; + +if (desc->desc0.rx.late_coll) + x->rx_collision++; + +if (desc->desc0.rx.crc_err) + x->rx_crc++; + + ret = discard_frame; + } + +if (desc->desc0.rx.len_err) { + ret = discard_frame; + } +if (desc->desc0.rx.mii_err) { + ret = discard_frame; + } + +return ret; +} + +int desc_get_own (struct dma_desc *desc) +{ +return desc->desc0.all &0x80000000 ; +} + +int desc_get_tx_ls (struct dma_desc *desc) +{ +return desc->desc1.tx.last_seg; +} + +int sunxi_geth_register (void *iobase,int version,unsigned int div) +{ + hwdev.ver = version; + hwdev.iobase = iobase; + hwdev.mdc_div = div; + +return 0 ; +} + +int sunxi_mac_reset (void *iobase,void (*delay)(int ),int n) +{ +unsigned int value; + +/* DMA SW reset */ + value =readl (iobase +GETH_BASIC_CTL1 ); + value |=SOFT_RST ; +writel (value, iobase +GETH_BASIC_CTL1 ); + +delay (n); + +return !!(readl (iobase +GETH_BASIC_CTL1 ) &SOFT_RST ); +}drivers/net/ethernet/allwinnertmp/sunxi-gmac.c new file +2240
-0@@ -0,0 +1,2240 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac.c +* +* Copyright © 2016-2018, fuzhaoke +* Author: fuzhaoke <[email protected]> +* +* This file is provided under a dual BSD/GPL license. When using or +* redistributing this file, you may do so under either license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +//#include <linux/clk.h> +//#include <linux/clk-provider.h> +#include <linux/mii.h> +#include <linux/gpio.h> +#include <linux/crc32.h> +#include <linux/skbuff.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +//#include <linux/pinctrl/consumer.h> +//#include <linux/pinctrl/pinctrl.h> +#include <linux/crypto.h> +#include <crypto/algapi.h> +#include <crypto/hash.h> +#include <linux/err.h> +#include <linux/scatterlist.h> +//#include <linux/regulator/consumer.h> +#include <linux/of_net.h> +//#include <linux/of_gpio.h> +#include <linux/io.h> +//#include <linux/sunxi-sid.h> +//#include <linux/sunxi-gpio.h> +//#include <linux/reset.h> +#include "sunxi-gmac.h" + +#define SUNXI_GMAC_VERSION "1.0.0" + +#define DMA_DESC_RX 256 +#define DMA_DESC_TX 256 +#define BUDGET (dma_desc_rx / 4) +#define TX_THRESH (dma_desc_tx / 4) + +#define HASH_TABLE_SIZE 64 +#define MAX_BUF_SZ (SZ_2K - 1) + +#define POWER_CHAN_NUM 3 + +#undef PKT_DEBUG +#undef DESC_PRINT + +#define circ_cnt (head, tail, size) (((head) > (tail)) ? \ + ((head) - (tail)) : \ + ((head) - (tail)) & ((size) - 1)) + +#define circ_space (head, tail, size) circ_cnt((tail), ((head) + 1), (size)) + +#define circ_inc (n, s) (((n) + 1) % (s)) + +#define GETH_MAC_ADDRESS "00:00:00:00:00:00" +static char *mac_str =GETH_MAC_ADDRESS ; +module_param (mac_str, charp,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (mac_str,"MAC Address String.(xx:xx:xx:xx:xx:xx)" ); + +static int rxmode =1 ; +module_param (rxmode, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (rxmode,"DMA threshold control value" ); + +static int txmode =1 ; +module_param (txmode, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (txmode,"DMA threshold control value" ); + +static int pause =0x400 ; +module_param (pause, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (pause,"Flow Control Pause Time" ); + +#define TX_TIMEO 5000 +static int watchdog =TX_TIMEO ; +module_param (watchdog, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"Transmit timeout in milliseconds" ); + +static int dma_desc_rx =DMA_DESC_RX ; +module_param (dma_desc_rx, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"The number of receive's descriptors" ); + +static int dma_desc_tx =DMA_DESC_TX ; +module_param (dma_desc_tx, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (watchdog,"The number of transmit's descriptors" ); + +/* - 0: Flow Off +* - 1: Rx Flow +* - 2: Tx Flow +* - 3: Rx & Tx Flow +*/ +static int flow_ctrl; +module_param (flow_ctrl, int,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (flow_ctrl,"Flow control [0: off, 1: rx, 2: tx, 3: both]" ); + +struct geth_priv { +struct dma_desc *dma_tx; +struct sk_buff **tx_sk; +unsigned int tx_clean; +unsigned int tx_dirty; +dma_addr_t dma_tx_phy; + +unsigned long buf_sz; + +struct dma_desc *dma_rx; +struct sk_buff **rx_sk; +unsigned int rx_clean; +unsigned int rx_dirty; +dma_addr_t dma_rx_phy; + +struct net_device *ndev; +struct device *dev; +struct napi_struct napi; + +struct geth_extra_stats xstats; + +struct mii_bus *mii; +int link; +int speed; +int duplex; +#define INT_PHY 0 +#define EXT_PHY 1 +int phy_ext; +phy_interface_t phy_interface; + +void __iomem *base; +void __iomem *base_phy; +/* +struct clk *geth_clk; +struct clk *ephy_clk; +struct reset_control *reset; +struct pinctrl *pinctrl; +*/ +struct regulator *gmac_power[POWER_CHAN_NUM ]; +bool is_suspend; +int phyrst; +u8 rst_active_low; +/* definition spinlock */ +spinlock_t lock; +spinlock_t tx_lock; + +/* whether using ephy_clk */ +int use_ephy_clk; +int phy_addr; + +/* adjust transmit clock delay, value: 0~7 */ +/* adjust receive clock delay, value: 0~31 */ +unsigned int tx_delay; +unsigned int rx_delay; + +/* resume work */ +struct work_struct eth_work; +}; + +static u64 geth_dma_mask =DMA_BIT_MASK (32 ); + +void sunxi_udelay (int n) +{ +udelay (n); +} + +static int geth_stop (struct net_device *ndev); +static int geth_open (struct net_device *ndev); +static void geth_tx_complete (struct geth_priv *priv); +static void geth_rx_refill (struct net_device *ndev); + +#ifdef CONFIG_GETH_ATTRS +static ssize_t adjust_bgs_show (struct device *dev,struct device_attribute *attr,char *buf) +{ +int value =0 ; +u32 efuse_value; +struct net_device *ndev =to_net_dev (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (priv->phy_ext ==INT_PHY ) { + value =readl (priv->base_phy) >>28 ; +if (sunxi_efuse_read (EFUSE_OEM_NAME , &efuse_value) !=0 ) +pr_err ("get PHY efuse fail!\n" ); + else +#if IS_ENABLED (CONFIG_ARCH_SUN50IW2 ) + value = value - ((efuse_value >>24 ) &0x0F ); +#else +pr_warn ("miss config come from efuse!\n" ); +#endif + } + +return sprintf (buf,"bgs: %d\n" , value); +} + +static ssize_t adjust_bgs_write (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +unsigned int out =0 ; +struct net_device *ndev =to_net_dev (dev); +struct geth_priv *priv =netdev_priv (ndev); +u32 clk_value =readl (priv->base_phy); +u32 efuse_value; + + out =simple_strtoul (buf,NULL ,10 ); + +if (priv->phy_ext ==INT_PHY ) { + clk_value &= ~(0xF <<28 ); +if (sunxi_efuse_read (EFUSE_OEM_NAME , &efuse_value) !=0 ) +pr_err ("get PHY efuse fail!\n" ); + else +#if IS_ENABLED (CONFIG_ARCH_SUN50IW2 ) + clk_value |= (((efuse_value >>24 ) &0x0F ) + out) <<28 ; +#else +pr_warn ("miss config come from efuse!\n" ); +#endif + } + +writel (clk_value, priv->base_phy); + +return count; +} + +static struct device_attribute adjust_reg[] = { +__ATTR (adjust_bgs,0664 , adjust_bgs_show, adjust_bgs_write), +}; + +static int geth_create_attrs (struct net_device *ndev) +{ +int j, ret; + +for (j =0 ; j <ARRAY_SIZE (adjust_reg); j++) { + ret =device_create_file (&ndev->dev, &adjust_reg[j]); +if (ret) + goto sysfs_failed; + } + goto succeed; + +sysfs_failed: +while (j--) +device_remove_file (&ndev->dev, &adjust_reg[j]); +succeed: +return ret; +} +#endif + +#ifdef DEBUG +static void desc_print (struct dma_desc *desc,int size) +{ +#ifdef DESC_PRINT +int i; + +for (i =0 ; i < size; i++) { +u32 *x = (u32 *)(desc + i); + +pr_info ("\t%d [0x%08lx]: %08x %08x %08x %08x\n" , + i, (unsigned long )(&desc[i]), + x[0 ], x[1 ], x[2 ], x[3 ]); + } +pr_info ("\n" ); +#endif +} +#endif + +static ssize_t extra_tx_stats_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"tx_underflow: %lu\ntx_carrier: %lu\n" +"tx_losscarrier: %lu\nvlan_tag: %lu\n" +"tx_deferred: %lu\ntx_vlan: %lu\n" +"tx_jabber: %lu\ntx_frame_flushed: %lu\n" +"tx_payload_error: %lu\ntx_ip_header_error: %lu\n\n" , + priv->xstats.tx_underflow, priv->xstats.tx_carrier, + priv->xstats.tx_losscarrier, priv->xstats.vlan_tag, + priv->xstats.tx_deferred, priv->xstats.tx_vlan, + priv->xstats.tx_jabber, priv->xstats.tx_frame_flushed, + priv->xstats.tx_payload_error, priv->xstats.tx_ip_header_error); +} +static DEVICE_ATTR(extra_tx_stats, 0444, extra_tx_stats_show, NULL); + +static ssize_t extra_rx_stats_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"rx_desc: %lu\nsa_filter_fail: %lu\n" +"overflow_error: %lu\nipc_csum_error: %lu\n" +"rx_collision: %lu\nrx_crc: %lu\n" +"dribbling_bit: %lu\nrx_length: %lu\n" +"rx_mii: %lu\nrx_multicast: %lu\n" +"rx_gmac_overflow: %lu\nrx_watchdog: %lu\n" +"da_rx_filter_fail: %lu\nsa_rx_filter_fail: %lu\n" +"rx_missed_cntr: %lu\nrx_overflow_cntr: %lu\n" +"rx_vlan: %lu\n\n" , + priv->xstats.rx_desc, priv->xstats.sa_filter_fail, + priv->xstats.overflow_error, priv->xstats.ipc_csum_error, + priv->xstats.rx_collision, priv->xstats.rx_crc, + priv->xstats.dribbling_bit, priv->xstats.rx_length, + priv->xstats.rx_mii, priv->xstats.rx_multicast, + priv->xstats.rx_gmac_overflow, priv->xstats.rx_length, + priv->xstats.da_rx_filter_fail, priv->xstats.sa_rx_filter_fail, + priv->xstats.rx_missed_cntr, priv->xstats.rx_overflow_cntr, + priv->xstats.rx_vlan); +} +static DEVICE_ATTR(extra_rx_stats, 0444, extra_rx_stats_show, NULL); + +static ssize_t gphy_test_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =dev_get_drvdata (dev); + +if (!dev) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return 0 ; + } + +return sprintf (buf,"Usage:\necho [0/1/2/3/4] > gphy_test\n" +"0 - Normal Mode\n" +"1 - Transmit Jitter Test\n" +"2 - Transmit Jitter Test(MASTER mode)\n" +"3 - Transmit Jitter Test(SLAVE mode)\n" +"4 - Transmit Distortion Test\n\n" ); +} + +static ssize_t gphy_test_store (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); +u16 value =0 ; +int ret =0 ; +u16 data =0 ; + +if (!dev) { +pr_err ("Argument is invalid\n" ); +return count; + } + +if (!ndev) { +pr_err ("Net device is null\n" ); +return count; + } + + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_CTRL1000 ); + + ret =kstrtou16 (buf,0 , &value); +if (ret) +return ret; + +if (value >=0 && value <=4 ) { + data &= ~(0x7 <<13 ); + data |= value <<13 ; +sunxi_mdio_write (priv->base, priv->phy_addr,MII_CTRL1000 , data); +pr_info ("Set MII_CTRL1000(0x09) Reg: 0x%x\n" , data); + }else { +pr_info ("unknown value (%d)\n" , value); + } + +return count; +} + +static DEVICE_ATTR(gphy_test, 0664, gphy_test_show, gphy_test_store); + +static ssize_t mii_reg_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct net_device *ndev =NULL ; +struct geth_priv *priv =NULL ; + +if (dev ==NULL ) { +pr_err ("Argment is invalid\n" ); +return 0 ; + } + + ndev =dev_get_drvdata (dev); +if (ndev ==NULL ) { +pr_err ("Net device is null\n" ); +return 0 ; + } + + priv =netdev_priv (ndev); +if (priv ==NULL ) { +pr_err ("geth_priv is null\n" ); +return 0 ; + } + +if (!netif_running (ndev)) { +pr_warn ("eth is down!\n" ); +return 0 ; + } + +return sprintf (buf, +"Current MII Registers:\n" +"BMCR[0x%02x] = 0x%04x,\t\tBMSR[0x%02x] = 0x%04x,\t\tPHYSID1[0x%02x] = 0x%04x\n" +"PHYSID2[0x%02x] = 0x%04x,\t\tADVERTISE[0x%02x] = 0x%04x,\tLPA[0x%02x] = 0x%04x\n" +"EXPANSION[0x%02x] = 0x%04x,\tCTRL1000[0x%02x] = 0x%04x,\tSTAT1000[0x%02x] = 0x%04x\n" , +MII_BMCR ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ), +MII_BMSR ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMSR ), +MII_PHYSID1 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_PHYSID1 ), +MII_PHYSID2 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_PHYSID2 ), +MII_ADVERTISE ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_ADVERTISE ), +MII_LPA ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_LPA ), +MII_EXPANSION ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_EXPANSION ), +MII_CTRL1000 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_CTRL1000 ), +MII_STAT1000 ,sunxi_mdio_read (priv->base, priv->phy_addr,MII_STAT1000 )); +} +static DEVICE_ATTR(mii_reg, 0444, mii_reg_show, NULL); + +static ssize_t loopback_test_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +return sprintf (buf,"Usage:\necho [0/1/2] > loopback_test\n" +"0 - Normal Mode\n" +"1 - Mac loopback test mode\n" +"2 - Phy loopback test mode\n" ); +} + +static ssize_t loopback_test_store (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ +struct net_device *ndev =NULL ; +struct geth_priv *priv =NULL ; +u16 value =0 ; +int ret =0 ; +u16 data =0 ; + +if (dev ==NULL ) { +pr_err ("Argment is invalid\n" ); +return count; + } + + ndev =dev_get_drvdata (dev); +if (ndev ==NULL ) { +pr_err ("Net device is null\n" ); +return count; + } + + priv =netdev_priv (ndev); +if (priv ==NULL ) { +pr_err ("geth_priv is null\n" ); +return count; + } + +if (!netif_running (ndev)) { +pr_warn ("eth is down!\n" ); +return count; + } + + ret =kstrtou16 (buf,0 , &value); +if (ret) +return ret; + +if (value ==0 ) {/* normal mode */ +/* clear mac loopback */ +sunxi_mac_loopback (priv->base,0 ); + +/* clear phy loopback */ + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data & ~BMCR_LOOPBACK ); + }else if (value ==1 ) {/* mac loopback test mode */ + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data & ~BMCR_LOOPBACK ); + +sunxi_mac_loopback (priv->base,1 ); + }else if (value ==2 ) {/* phy loopback test mode */ +sunxi_mac_loopback (priv->base,0 ); + + data =sunxi_mdio_read (priv->base, priv->phy_addr,MII_BMCR ); +sunxi_mdio_write (priv->base, priv->phy_addr,MII_BMCR , data |BMCR_LOOPBACK ); + }else { +pr_err ("Undefined value (%d)\n" , value); + } + +return count; +} +static DEVICE_ATTR(loopback_test, 0664, loopback_test_show, loopback_test_store); + +static int geth_power_on (struct geth_priv *priv) +{ +int value; + + value =readl (priv->base_phy); +if (priv->phy_ext ==INT_PHY ) { + value |= (1 <<15 ); + value &= ~(1 <<16 ); + value |= (3 <<17 ); + }else { + value &= ~(1 <<15 ); +/* +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +if (regulator_enable(priv->gmac_power[i]) != 0) { +pr_err("gmac-power%d enable error\n", i); +return -EINVAL; +} +} +*/ + } + +writel (value, priv->base_phy); + +return 0 ; +} + +static void geth_power_off (struct geth_priv *priv) +{ +int value; + +if (priv->phy_ext ==INT_PHY ) { + value =readl (priv->base_phy); + value |= (1 <<16 ); +writel (value, priv->base_phy); + }else { +/* +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_disable(priv->gmac_power[i]); +} +*/ + } +} + +/* PHY interface operations */ +static int geth_mdio_read (struct mii_bus *bus,int phyaddr,int phyreg) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +return (int )sunxi_mdio_read (priv->base, phyaddr, phyreg); +} + +static int geth_mdio_write (struct mii_bus *bus,int phyaddr, +int phyreg,u16 data) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +sunxi_mdio_write (priv->base, phyaddr, phyreg, data); + +return 0 ; +} + +static int geth_mdio_reset (struct mii_bus *bus) +{ +struct net_device *ndev = bus->priv; +struct geth_priv *priv =netdev_priv (ndev); + +return sunxi_mdio_reset (priv->base); +} + +static void geth_adjust_link (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; +unsigned long flags; +int new_state =0 ; + +if (!phydev) +return ; + +spin_lock_irqsave (&priv->lock, flags); +if (phydev->link) { +/* Now we make sure that we can be in full duplex mode. +* If not, we operate in half-duplex mode. +*/ +if (phydev->duplex != priv->duplex) { + new_state =1 ; + priv->duplex = phydev->duplex; + } +/* Flow Control operation */ +if (phydev->pause) +sunxi_flow_ctrl (priv->base, phydev->duplex, + flow_ctrl, pause); + +if (phydev->speed != priv->speed) { + new_state =1 ; + priv->speed = phydev->speed; + } + +if (priv->link ==0 ) { + new_state =1 ; + priv->link = phydev->link; + } + +if (new_state) +sunxi_set_link_mode (priv->base, priv->duplex, priv->speed); + +#ifdef LOOPBACK_DEBUG + phydev->state =PHY_FORCING ; +#endif + + }else if (priv->link != phydev->link) { + new_state =1 ; + priv->link =0 ; + priv->speed =0 ; + priv->duplex =-1 ; + } + +if (new_state) +phy_print_status (phydev); + +spin_unlock_irqrestore (&priv->lock, flags); +} + +static int geth_phy_init (struct net_device *ndev) +{ +int value; +struct mii_bus *new_bus; +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; + +/* Fixup the phy interface type */ +if (priv->phy_ext ==INT_PHY ) { + priv->phy_interface =PHY_INTERFACE_MODE_MII ; + }else { +/* If config gpio to reset the phy device, we should reset it */ +/* +if (gpio_is_valid(priv->phyrst)) { +gpio_direction_output(priv->phyrst, +priv->rst_active_low); +msleep(50); +gpio_direction_output(priv->phyrst, +!priv->rst_active_low); +msleep(50); +} +*/ + } + +if (priv->is_suspend && phydev) + goto resume; + + new_bus =mdiobus_alloc (); +if (!new_bus) { +netdev_err (ndev,"Failed to alloc new mdio bus\n" ); +return -ENOMEM ; + } + + new_bus->name =dev_name (priv->dev); + new_bus->read = &geth_mdio_read; + new_bus->write = &geth_mdio_write; + new_bus->reset = &geth_mdio_reset; +snprintf (new_bus->id,MII_BUS_ID_SIZE ,"%s-%x" , new_bus->name,0 ); + + new_bus->parent = priv->dev; + new_bus->priv = ndev; + +if (mdiobus_register (new_bus)) { +pr_err ("%s: Cannot register as MDIO bus\n" , new_bus->name); + goto reg_fail; + } + + priv->mii = new_bus; + + { +int addr; + +for (addr =0 ; addr <PHY_MAX_ADDR ; addr++) { +struct phy_device *phydev_tmp =mdiobus_get_phy (new_bus, addr); + +if (phydev_tmp && (phydev_tmp->phy_id !=0x00 )) { + phydev = phydev_tmp; + priv->phy_addr = addr; +break ; + } + } + } + +if (!phydev) { +netdev_err (ndev,"No PHY found!\n" ); + goto err; + } + + phydev->irq =PHY_POLL ; + + value =phy_connect_direct (ndev, phydev, &geth_adjust_link, priv->phy_interface); +if (value) { +netdev_err (ndev,"Could not attach to PHY\n" ); + goto err; + }else { +netdev_info (ndev,"%s: Type(%d) PHY ID %08x at %d IRQ %s (%s)\n" , + ndev->name, phydev->interface, phydev->phy_id, + phydev->mdio.addr,"poll" ,dev_name (&phydev->mdio.dev)); + } + +//phydev->supported &= PHY_GBIT_FEATURES; + phydev->is_gigabit_capable =1 ; +//phydev->advertising = phydev->supported; + +resume: +phy_write (phydev,MII_BMCR ,BMCR_RESET ); +while (BMCR_RESET &phy_read (phydev,MII_BMCR )) +msleep (30 ); + + value =phy_read (phydev,MII_BMCR ); +phy_write (phydev,MII_BMCR , (value & ~BMCR_PDOWN )); + +if (priv->phy_ext ==INT_PHY ) { +/* EPHY Initial */ +phy_write (phydev,0x1f ,0x0100 );/* switch to page 1 */ +phy_write (phydev,0x12 ,0x4824 );/* Disable APS */ +phy_write (phydev,0x1f ,0x0200 );/* switchto page 2 */ +phy_write (phydev,0x18 ,0x0000 );/* PHYAFE TRX optimization */ +phy_write (phydev,0x1f ,0x0600 );/* switchto page 6 */ +phy_write (phydev,0x14 ,0x708F );/* PHYAFE TX optimization */ +phy_write (phydev,0x19 ,0x0000 ); +phy_write (phydev,0x13 ,0xf000 );/* PHYAFE RX optimization */ +phy_write (phydev,0x15 ,0x1530 ); +phy_write (phydev,0x1f ,0x0800 );/* switch to page 8 */ +phy_write (phydev,0x18 ,0x00bc );/* PHYAFE TRX optimization */ +phy_write (phydev,0x1f ,0x0100 );/* switchto page 1 */ +/* reg 0x17 bit3,set 0 to disable iEEE */ +phy_write (phydev,0x17 ,phy_read (phydev,0x17 ) & (~(1 <<3 ))); +phy_write (phydev,0x1f ,0x0000 );/* switch to page 0 */ + } +if (priv->is_suspend) +phy_init_hw (phydev); + +return 0 ; + +err: +mdiobus_unregister (new_bus); +reg_fail: +mdiobus_free (new_bus); + +return -EINVAL ; +} + +static int geth_phy_release (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct phy_device *phydev = ndev->phydev; +int value =0 ; + +/* Stop and disconnect the PHY */ +if (phydev) +phy_stop (phydev); + + priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; + +if (phydev) { + value =phy_read (phydev,MII_BMCR ); +phy_write (phydev,MII_BMCR , (value |BMCR_PDOWN )); + } + +if (priv->is_suspend) +return 0 ; + +if (phydev) { +phy_disconnect (phydev); + ndev->phydev =NULL ; + } + +if (priv->mii) { +mdiobus_unregister (priv->mii); + priv->mii->priv =NULL ; +mdiobus_free (priv->mii); + priv->mii =NULL ; + } + +return 0 ; +} + +static void geth_rx_refill (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct dma_desc *desc; +struct sk_buff *sk =NULL ; +dma_addr_t paddr; + +while (circ_space (priv->rx_clean, priv->rx_dirty, dma_desc_rx) >0 ) { +int entry = priv->rx_clean; + +/* Find the dirty's desc and clean it */ + desc = priv->dma_rx + entry; + +if (priv->rx_sk[entry] ==NULL ) { + sk =netdev_alloc_skb_ip_align (ndev, priv->buf_sz); + +if (unlikely (sk ==NULL )) +break ; + + priv->rx_sk[entry] = sk; + paddr =dma_map_single (priv->dev, sk->data, + priv->buf_sz,DMA_FROM_DEVICE ); +desc_buf_set (desc, paddr, priv->buf_sz); + } + +/* sync memery */ +wmb (); +desc_set_own (desc); + priv->rx_clean =circ_inc (priv->rx_clean, dma_desc_rx); + } +} + +/* geth_dma_desc_init - initialize the RX/TX descriptor list +* @ndev: net device structure +* Description: initialize the list for dma. +*/ +static int geth_dma_desc_init (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int buf_sz; + + priv->rx_sk =kzalloc (sizeof (struct sk_buff *) * dma_desc_rx, +GFP_KERNEL ); +if (!priv->rx_sk) +return -ENOMEM ; + + priv->tx_sk =kzalloc (sizeof (struct sk_buff *) * dma_desc_tx, +GFP_KERNEL ); +if (!priv->tx_sk) + goto tx_sk_err; + +/* Set the size of buffer depend on the MTU & max buf size */ + buf_sz =MAX_BUF_SZ ; + + priv->dma_tx =dma_alloc_coherent (priv->dev, + dma_desc_tx * +sizeof (struct dma_desc ), + &priv->dma_tx_phy, +GFP_KERNEL ); +if (!priv->dma_tx) + goto dma_tx_err; + + priv->dma_rx =dma_alloc_coherent (priv->dev, + dma_desc_rx * +sizeof (struct dma_desc ), + &priv->dma_rx_phy, +GFP_KERNEL ); +if (!priv->dma_rx) + goto dma_rx_err; + + priv->buf_sz = buf_sz; + +return 0 ; + +dma_rx_err: +dma_free_coherent (priv->dev, dma_desc_rx *sizeof (struct dma_desc ), + priv->dma_tx, priv->dma_tx_phy); +dma_tx_err: +kfree (priv->tx_sk); +tx_sk_err: +kfree (priv->rx_sk); + +return -ENOMEM ; +} + +static void geth_free_rx_sk (struct geth_priv *priv) +{ +int i; + +for (i =0 ; i < dma_desc_rx; i++) { +if (priv->rx_sk[i] !=NULL ) { +struct dma_desc *desc = priv->dma_rx + i; + +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc), +DMA_FROM_DEVICE ); +dev_kfree_skb_any (priv->rx_sk[i]); + priv->rx_sk[i] =NULL ; + } + } +} + +static void geth_free_tx_sk (struct geth_priv *priv) +{ +int i; + +for (i =0 ; i < dma_desc_tx; i++) { +if (priv->tx_sk[i] !=NULL ) { +struct dma_desc *desc = priv->dma_tx + i; + +if (desc_buf_get_addr (desc)) +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc), +DMA_TO_DEVICE ); +dev_kfree_skb_any (priv->tx_sk[i]); + priv->tx_sk[i] =NULL ; + } + } +} + +static void geth_free_dma_desc (struct geth_priv *priv) +{ +/* Free the region of consistent memory previously allocated for the DMA */ +dma_free_coherent (priv->dev, dma_desc_tx *sizeof (struct dma_desc ), + priv->dma_tx, priv->dma_tx_phy); +dma_free_coherent (priv->dev, dma_desc_rx *sizeof (struct dma_desc ), + priv->dma_rx, priv->dma_rx_phy); + +kfree (priv->rx_sk); +kfree (priv->tx_sk); +} + +#if IS_ENABLED (CONFIG_PM ) +/* +static int geth_select_gpio_state(struct pinctrl *pctrl, char *name) +{ +int ret = 0; +struct pinctrl_state *pctrl_state = NULL; + +pctrl_state = pinctrl_lookup_state(pctrl, name); +if (IS_ERR(pctrl_state)) { +pr_err("gmac pinctrl_lookup_state(%s) failed! return %p\n", +name, pctrl_state); +return -EINVAL; +} + +ret = pinctrl_select_state(pctrl, pctrl_state); +if (ret < 0) +pr_err("gmac pinctrl_select_state(%s) failed! return %d\n", +name, ret); + +return ret; +} +*/ +static int geth_suspend (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +cancel_work_sync (&priv->eth_work); + +if (!ndev || !netif_running (ndev)) +return 0 ; + + priv->is_suspend = true; + +spin_lock (&priv->lock); +netif_device_detach (ndev); +spin_unlock (&priv->lock); + +geth_stop (ndev); +/* +if (priv->phy_ext == EXT_PHY) + +geth_select_gpio_state(priv->pinctrl, PINCTRL_STATE_SLEEP); +*/ +return 0 ; +} + +static void geth_resume_work (struct work_struct *work) +{ + struct geth_priv *priv = container_of(work, struct geth_priv, eth_work); +struct net_device *ndev = priv->ndev; +int ret =0 ; + +if (!netif_running (ndev)) +return ; +/* +if (priv->phy_ext == EXT_PHY) +geth_select_gpio_state(priv->pinctrl, PINCTRL_STATE_DEFAULT); +*/ +spin_lock (&priv->lock); +netif_device_attach (ndev); +spin_unlock (&priv->lock); + +#if IS_ENABLED (CONFIG_SUNXI_EPHY ) +if (!ephy_is_enable ()) { +pr_info ("[geth_resume] ephy is not enable, waiting...\n" ); +msleep (2000 ); +if (!ephy_is_enable ()) { +netdev_err (ndev,"Wait for ephy resume timeout.\n" ); +return ; + } + } +#endif + + ret =geth_open (ndev); +if (!ret) + priv->is_suspend = false; +} + +static void geth_resume (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct geth_priv *priv =netdev_priv (ndev); + +schedule_work (&priv->eth_work); +} + +static int geth_freeze (struct device *dev) +{ +return 0 ; +} + +static int geth_restore (struct device *dev) +{ +return 0 ; +} + +static const struct dev_pm_ops geth_pm_ops = { + .complete = geth_resume, + .prepare = geth_suspend, + .suspend =NULL , + .resume =NULL , + .freeze = geth_freeze, + .restore = geth_restore, +}; +#else +static const struct dev_pm_ops geth_pm_ops; +#endif /* CONFIG_PM */ + +#define sunxi_get_soc_chipid (x) {} +static void geth_chip_hwaddr (u8 *addr) +{ +#define MD5_SIZE 16 +#define CHIP_SIZE 16 + +struct crypto_ahash *tfm; +struct ahash_request *req; +struct scatterlist sg; +u8 result[MD5_SIZE ]; +u8 chipid[CHIP_SIZE ]; +int i =0 ; +int ret =-1 ; + +memset (chipid,0 ,sizeof (chipid)); +memset (result,0 ,sizeof (result)); + +sunxi_get_soc_chipid ((u8 *)chipid); + + tfm =crypto_alloc_ahash ("md5" ,0 ,CRYPTO_ALG_ASYNC ); +if (IS_ERR (tfm)) { +pr_err ("Failed to alloc md5\n" ); +return ; + } + + req =ahash_request_alloc (tfm,GFP_KERNEL ); +if (!req) + goto out; + +ahash_request_set_callback (req,0 ,NULL ,NULL ); + + ret =crypto_ahash_init (req); +if (ret) { +pr_err ("crypto_ahash_init() failed\n" ); + goto out; + } + +sg_init_one (&sg, chipid,sizeof (chipid)); +ahash_request_set_crypt (req, &sg, result,sizeof (chipid)); + ret =crypto_ahash_update (req); +if (ret) { +pr_err ("crypto_ahash_update() failed for id\n" ); + goto out; + } + + ret =crypto_ahash_final (req); +if (ret) { +pr_err ("crypto_ahash_final() failed for result\n" ); + goto out; + } + +ahash_request_free (req); + +/* Choose md5 result's [0][2][4][6][8][10] byte as mac address */ +for (i =0 ; i <ETH_ALEN ; i++) + addr[i] = result[2 * i]; + addr[0 ] &=0xfe ;/* clear multicast bit */ + addr[0 ] |=0x02 ;/* set local assignment bit (IEEE802) */ + +out: +crypto_free_ahash (tfm); +} + +static void geth_check_addr (struct net_device *ndev,unsigned char *mac) +{ +int i; +char *p = mac; + +if (!is_valid_ether_addr (ndev->dev_addr)) { +for (i =0 ; i <ETH_ALEN ; i++, p++) + ndev->dev_addr[i] =simple_strtoul (p, &p,16 ); + +if (!is_valid_ether_addr (ndev->dev_addr)) +geth_chip_hwaddr (ndev->dev_addr); + +if (!is_valid_ether_addr (ndev->dev_addr)) { +random_ether_addr (ndev->dev_addr); +pr_warn ("%s: Use random mac address\n" , ndev->name); + } + } +} + +static int geth_clk_enable (struct geth_priv *priv) +{ +int ret; +phy_interface_t phy_interface =0 ; +u32 clk_value; +/*u32 efuse_value;*/ +/* +ret = reset_control_deassert(priv->reset); +if (ret) { +pr_err("deassert gmac rst failed!\n"); +return ret; +} + +ret = clk_prepare_enable(priv->geth_clk); +if (ret) { +pr_err("try to enable geth_clk failed!\n"); +goto assert_reset; +} + +if (((priv->phy_ext == INT_PHY) || priv->use_ephy_clk) +&& !IS_ERR_OR_NULL(priv->ephy_clk)) { +ret = clk_prepare_enable(priv->ephy_clk); +if (ret) { +pr_err("try to enable ephy_clk failed!\n"); +goto ephy_clk_disable; +} +} +*/ + phy_interface = priv->phy_interface; + + clk_value =readl (priv->base_phy); +if (phy_interface ==PHY_INTERFACE_MODE_RGMII ) + clk_value |=0x00000004 ; +else + clk_value &= (~0x00000004 ); + + clk_value &= (~0x00002003 ); +if (phy_interface ==PHY_INTERFACE_MODE_RGMII + || phy_interface ==PHY_INTERFACE_MODE_GMII ) + clk_value |=0x00000002 ; +else if (phy_interface ==PHY_INTERFACE_MODE_RMII ) + clk_value |=0x00002001 ; + +/*if (priv->phy_ext == INT_PHY) { +if (0 != sunxi_efuse_read(EFUSE_OEM_NAME, &efuse_value)) +pr_err("get PHY efuse fail!\n"); +else +#if IS_ENABLED(CONFIG_ARCH_SUN50IW2) +clk_value |= (((efuse_value >> 24) & 0x0F) + 3) << 28; +#else +pr_warn("miss config come from efuse!\n"); +#endif +}*/ + +/* Adjust Tx/Rx clock delay */ + clk_value &= ~(0x07 <<10 ); + clk_value |= ((priv->tx_delay &0x07 ) <<10 ); + clk_value &= ~(0x1F <<5 ); + clk_value |= ((priv->rx_delay &0x1F ) <<5 ); + +writel (clk_value, priv->base_phy); + +return 0 ; +/* +ephy_clk_disable: +clk_disable_unprepare(priv->ephy_clk); +assert_reset: +reset_control_assert(priv->reset); +*/ +return ret; +} + +static void geth_clk_disable (struct geth_priv *priv) +{ +/* +if (((priv->phy_ext == INT_PHY) || priv->use_ephy_clk) +&& !IS_ERR_OR_NULL(priv->ephy_clk)) +clk_disable_unprepare(priv->ephy_clk); + +clk_disable_unprepare(priv->geth_clk); +reset_control_assert(priv->reset); +*/ +} + +static void geth_tx_err (struct geth_priv *priv) +{ +netif_stop_queue (priv->ndev); + +sunxi_stop_tx (priv->base); + +geth_free_tx_sk (priv); +memset (priv->dma_tx,0 , dma_desc_tx *sizeof (struct dma_desc )); +desc_init_chain (priv->dma_tx, (unsigned long )priv->dma_tx_phy, dma_desc_tx); + priv->tx_dirty =0 ; + priv->tx_clean =0 ; +sunxi_start_tx (priv->base, priv->dma_tx_phy); + + priv->ndev->stats.tx_errors++; +netif_wake_queue (priv->ndev); +} + +static inline void geth_schedule (struct geth_priv *priv) +{ +if (likely (napi_schedule_prep (&priv->napi))) { +sunxi_int_disable (priv->base); +__napi_schedule (&priv->napi); + } +} + +static irqreturn_t geth_interrupt (int irq,void *dev_id) +{ +struct net_device *ndev = (struct net_device *)dev_id; +struct geth_priv *priv =netdev_priv (ndev); +int status; + +if (unlikely (!ndev)) { +pr_err ("%s: invalid ndev pointer\n" , __func__); +return IRQ_NONE ; + } + + status =sunxi_int_status (priv->base, (void *)(&priv->xstats)); + +if (likely (status == handle_tx_rx)) +geth_schedule (priv); +else if (unlikely (status == tx_hard_error_bump_tc)) +netdev_info (ndev,"Do nothing for bump tc\n" ); +else if (unlikely (status == tx_hard_error)) +geth_tx_err (priv); +else +netdev_info (ndev,"Do nothing.....\n" ); + +return IRQ_HANDLED ; +} + +static int geth_open (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +int ret =0 ; + + ret =geth_power_on (priv); +if (ret) { +netdev_err (ndev,"Power on is failed\n" ); + ret = -EINVAL ; + } + + ret =geth_clk_enable (priv); +if (ret) { +pr_err ("%s: clk enable is failed\n" , __func__); + ret = -EINVAL ; + } + +netif_carrier_off (ndev); + + ret =geth_phy_init (ndev); +if (ret) + goto err; + + ret =sunxi_mac_reset ((void *)priv->base, &sunxi_udelay,10000 ); +if (ret) { +netdev_err (ndev,"Initialize hardware error\n" ); + goto desc_err; + } + +sunxi_mac_init (priv->base, txmode, rxmode); +sunxi_set_umac (priv->base, ndev->dev_addr,0 ); + +if (!priv->is_suspend) { + ret =geth_dma_desc_init (ndev); +if (ret) { + ret = -EINVAL ; + goto desc_err; + } + } + +memset (priv->dma_tx,0 , dma_desc_tx *sizeof (struct dma_desc )); +memset (priv->dma_rx,0 , dma_desc_rx *sizeof (struct dma_desc )); + +desc_init_chain (priv->dma_rx, (unsigned long )priv->dma_rx_phy, dma_desc_rx); +desc_init_chain (priv->dma_tx, (unsigned long )priv->dma_tx_phy, dma_desc_tx); + + priv->rx_clean =0 ; + priv->rx_dirty =0 ; + priv->tx_clean =0 ; + priv->tx_dirty =0 ; +geth_rx_refill (ndev); + +/* Extra statistics */ +memset (&priv->xstats,0 ,sizeof (struct geth_extra_stats )); + +if (ndev->phydev) +phy_start (ndev->phydev); + +sunxi_start_rx (priv->base, (unsigned long )((struct dma_desc *) + priv->dma_rx_phy + priv->rx_dirty)); +sunxi_start_tx (priv->base, (unsigned long )((struct dma_desc *) + priv->dma_tx_phy + priv->tx_clean)); + +napi_enable (&priv->napi); +netif_start_queue (ndev); + +/* Enable the Rx/Tx */ +sunxi_mac_enable (priv->base); + +return 0 ; + +desc_err: +geth_phy_release (ndev); +err: +geth_clk_disable (priv); +if (priv->is_suspend) +napi_enable (&priv->napi); + +geth_power_off (priv); + +return ret; +} + +static int geth_stop (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); + +netif_stop_queue (ndev); +napi_disable (&priv->napi); + +netif_carrier_off (ndev); + +/* Release PHY resources */ +geth_phy_release (ndev); + +/* Disable Rx/Tx */ +sunxi_mac_disable (priv->base); + +geth_clk_disable (priv); +geth_power_off (priv); + +netif_tx_lock_bh (ndev); +/* Release the DMA TX/RX socket buffers */ +geth_free_rx_sk (priv); +geth_free_tx_sk (priv); +netif_tx_unlock_bh (ndev); + +/* Ensure that hareware have been stopped */ +if (!priv->is_suspend) +geth_free_dma_desc (priv); + +return 0 ; +} + +static void geth_tx_complete (struct geth_priv *priv) +{ +unsigned int entry =0 ; +struct sk_buff *skb =NULL ; +struct dma_desc *desc =NULL ; +int tx_stat; + +spin_lock (&priv->tx_lock); +while (circ_cnt (priv->tx_dirty, priv->tx_clean, dma_desc_tx) >0 ) { + entry = priv->tx_clean; + desc = priv->dma_tx + entry; + +/* Check if the descriptor is owned by the DMA. */ +if (desc_get_own (desc)) +break ; + +/* Verify tx error by looking at the last segment */ +if (desc_get_tx_ls (desc)) { + tx_stat =desc_get_tx_status (desc, (void *)(&priv->xstats)); + +if (likely (!tx_stat)) + priv->ndev->stats.tx_packets++; +else + priv->ndev->stats.tx_errors++; + } + +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc),DMA_TO_DEVICE ); + + skb = priv->tx_sk[entry]; + priv->tx_sk[entry] =NULL ; +desc_init (desc); + +/* Find next dirty desc */ + priv->tx_clean =circ_inc (entry, dma_desc_tx); + +if (unlikely (skb ==NULL )) +continue ; + +dev_kfree_skb (skb); + } + +if (unlikely (netif_queue_stopped (priv->ndev)) && +circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) > +TX_THRESH ) { +netif_wake_queue (priv->ndev); + } +spin_unlock (&priv->tx_lock); +} + +static netdev_tx_t geth_xmit (struct sk_buff *skb,struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int entry; +struct dma_desc *desc, *first; +unsigned int len, tmp_len =0 ; +int i, csum_insert; +int nfrags =skb_shinfo (skb)->nr_frags; +dma_addr_t paddr; + +spin_lock (&priv->tx_lock); +if (unlikely (circ_space (priv->tx_dirty, priv->tx_clean, + dma_desc_tx) < (nfrags +1 ))) { +if (!netif_queue_stopped (ndev)) { +netdev_err (ndev,"%s: BUG! Tx Ring full when queue awake\n" , __func__); +netif_stop_queue (ndev); + } +spin_unlock (&priv->tx_lock); + +return NETDEV_TX_BUSY ; + } + + csum_insert = (skb->ip_summed ==CHECKSUM_PARTIAL ); + entry = priv->tx_dirty; + first = priv->dma_tx + entry; + desc = priv->dma_tx + entry; + + len =skb_headlen (skb); + priv->tx_sk[entry] = skb; + +#ifdef PKT_DEBUG +printk ("======TX PKT DATA: ============\n" ); +/* dump the packet */ +print_hex_dump (KERN_DEBUG ,"skb->data: " ,DUMP_PREFIX_NONE , +16 ,1 , skb->data,64 , true); +#endif + +/* Every desc max size is 2K */ +while (len !=0 ) { + desc = priv->dma_tx + entry; + tmp_len = ((len >MAX_BUF_SZ ) ?MAX_BUF_SZ : len); + + paddr =dma_map_single (priv->dev, skb->data, tmp_len,DMA_TO_DEVICE ); +if (dma_mapping_error (priv->dev, paddr)) { +dev_kfree_skb (skb); +return -EIO ; + } +desc_buf_set (desc, paddr, tmp_len); +/* Don't set the first's own bit, here */ +if (first != desc) { + priv->tx_sk[entry] =NULL ; +desc_set_own (desc); + } + + entry =circ_inc (entry, dma_desc_tx); + len -= tmp_len; + } + +for (i =0 ; i < nfrags; i++) { +const skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; + + len =skb_frag_size (frag); + desc = priv->dma_tx + entry; + paddr =skb_frag_dma_map (priv->dev, frag,0 , len,DMA_TO_DEVICE ); +if (dma_mapping_error (priv->dev, paddr)) { +dev_kfree_skb (skb); +return -EIO ; + } + +desc_buf_set (desc, paddr, len); +desc_set_own (desc); + priv->tx_sk[entry] =NULL ; + entry =circ_inc (entry, dma_desc_tx); + } + + ndev->stats.tx_bytes += skb->len; + priv->tx_dirty = entry; +desc_tx_close (first, desc, csum_insert); + +desc_set_own (first); +spin_unlock (&priv->tx_lock); + +if (circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) <= + (MAX_SKB_FRAGS +1 )) { +netif_stop_queue (ndev); +if (circ_space (priv->tx_dirty, priv->tx_clean, dma_desc_tx) > +TX_THRESH ) +netif_wake_queue (ndev); + } + +#ifdef DEBUG +printk ("=======TX Descriptor DMA: 0x%08llx\n" , priv->dma_tx_phy); +printk ("Tx pointor: dirty: %d, clean: %d\n" , priv->tx_dirty, priv->tx_clean); +desc_print (priv->dma_tx, dma_desc_tx); +#endif +sunxi_tx_poll (priv->base); +geth_tx_complete (priv); + +return NETDEV_TX_OK ; +} + +static int geth_rx (struct geth_priv *priv,int limit) +{ +unsigned int rxcount =0 ; +unsigned int entry; +struct dma_desc *desc; +struct sk_buff *skb; +int status; +int frame_len; + +while (rxcount < limit) { + entry = priv->rx_dirty; + desc = priv->dma_rx + entry; + +if (desc_get_own (desc)) +break ; + + rxcount++; + priv->rx_dirty =circ_inc (priv->rx_dirty, dma_desc_rx); + +/* Get length & status from hardware */ + frame_len =desc_rx_frame_len (desc); + status =desc_get_rx_status (desc, (void *)(&priv->xstats)); + +netdev_dbg (priv->ndev,"Rx frame size %d, status: %d\n" , + frame_len, status); + + skb = priv->rx_sk[entry]; +if (unlikely (!skb)) { +netdev_err (priv->ndev,"Skb is null\n" ); + priv->ndev->stats.rx_dropped++; +break ; + } + +#ifdef PKT_DEBUG +printk ("======RX PKT DATA: ============\n" ); +/* dump the packet */ +print_hex_dump (KERN_DEBUG ,"skb->data: " ,DUMP_PREFIX_NONE , +16 ,1 , skb->data,64 , true); +#endif + +if (status == discard_frame) { +netdev_dbg (priv->ndev,"Get error pkt\n" ); + priv->ndev->stats.rx_errors++; +continue ; + } + +if (unlikely (status != llc_snap)) + frame_len -=ETH_FCS_LEN ; + + priv->rx_sk[entry] =NULL ; + +skb_put (skb, frame_len); +dma_unmap_single (priv->dev, (u32 )desc_buf_get_addr (desc), +desc_buf_get_len (desc),DMA_FROM_DEVICE ); + + skb->protocol =eth_type_trans (skb, priv->ndev); + + skb->ip_summed =CHECKSUM_UNNECESSARY ; +napi_gro_receive (&priv->napi, skb); + + priv->ndev->stats.rx_packets++; + priv->ndev->stats.rx_bytes += frame_len; + } + +#ifdef DEBUG +if (rxcount >0 ) { +printk ("======RX Descriptor DMA: 0x%08llx=\n" , priv->dma_rx_phy); +printk ("RX pointor: dirty: %d, clean: %d\n" , priv->rx_dirty, priv->rx_clean); +desc_print (priv->dma_rx, dma_desc_rx); + } +#endif +geth_rx_refill (priv->ndev); + +return rxcount; +} + +static int geth_poll (struct napi_struct *napi,int budget) +{ + struct geth_priv *priv = container_of(napi, struct geth_priv, napi); +int work_done =0 ; + +geth_tx_complete (priv); + work_done =geth_rx (priv, budget); + +if (work_done < budget) { +napi_complete (napi); +sunxi_int_enable (priv->base); + } + +return work_done; +} + +static int geth_change_mtu (struct net_device *ndev,int new_mtu) +{ +int max_mtu; + +if (netif_running (ndev)) { +pr_err ("%s: must be stopped to change its MTU\n" , ndev->name); +return -EBUSY ; + } + + max_mtu =SKB_MAX_HEAD (NET_SKB_PAD +NET_IP_ALIGN ); + +if ((new_mtu <46 ) || (new_mtu > max_mtu)) { +pr_err ("%s: invalid MTU, max MTU is: %d\n" , ndev->name, max_mtu); +return -EINVAL ; + } + + ndev->mtu = new_mtu; +netdev_update_features (ndev); + +return 0 ; +} + +static netdev_features_t geth_fix_features (struct net_device *ndev, +netdev_features_t features) +{ +return features; +} + +static void geth_set_rx_mode (struct net_device *ndev) +{ +struct geth_priv *priv =netdev_priv (ndev); +unsigned int value =0 ; + +pr_debug ("%s: # mcasts %d, # unicast %d\n" , + __func__,netdev_mc_count (ndev),netdev_uc_count (ndev)); + +spin_lock (&priv->lock); +if (ndev->flags &IFF_PROMISC ) { + value =GETH_FRAME_FILTER_PR ; + }else if ((netdev_mc_count (ndev) >HASH_TABLE_SIZE ) || + (ndev->flags &IFF_ALLMULTI )) { + value =GETH_FRAME_FILTER_PM ;/* pass all multi */ +sunxi_hash_filter (priv->base, ~0UL , ~0UL ); + }else if (!netdev_mc_empty (ndev)) { +u32 mc_filter[2 ]; +struct netdev_hw_addr *ha; + +/* Hash filter for multicast */ + value =GETH_FRAME_FILTER_HMC ; + +memset (mc_filter,0 ,sizeof (mc_filter)); +netdev_for_each_mc_addr (ha, ndev) { +/* The upper 6 bits of the calculated CRC are used to +* index the contens of the hash table +*/ +int bit_nr =bitrev32 (~crc32_le (~0 , ha->addr,6 )) >>26 ; +/* The most significant bit determines the register to +* use (H/L) while the other 5 bits determine the bit +* within the register. +*/ + mc_filter[bit_nr >>5 ] |=1 << (bit_nr &31 ); + } +sunxi_hash_filter (priv->base, mc_filter[0 ], mc_filter[1 ]); + } + +/* Handle multiple unicast addresses (perfect filtering)*/ +if (netdev_uc_count (ndev) >16 ) { +/* Switch to promiscuous mode is more than 8 addrs are required */ + value |=GETH_FRAME_FILTER_PR ; + }else { +int reg =1 ; +struct netdev_hw_addr *ha; + +netdev_for_each_uc_addr (ha, ndev) { +sunxi_set_umac (priv->base, ha->addr, reg); + reg++; + } + } + +#ifdef FRAME_FILTER_DEBUG +/* Enable Receive all mode (to debug filtering_fail errors) */ + value |=GETH_FRAME_FILTER_RA ; +#endif +sunxi_set_filter (priv->base, value); +spin_unlock (&priv->lock); +} + +static void geth_tx_timeout (struct net_device *ndev,unsigned int txqueue) +{ +struct geth_priv *priv =netdev_priv (ndev); + +geth_tx_err (priv); +} + +static int geth_ioctl (struct net_device *ndev,struct ifreq *rq,int cmd) +{ +if (!netif_running (ndev)) +return -EINVAL ; + +if (!ndev->phydev) +return -EINVAL ; + +return phy_mii_ioctl (ndev->phydev, rq, cmd); +} + +/* Configuration changes (passed on by ifconfig) */ +static int geth_config (struct net_device *ndev,struct ifmap *map) +{ +if (ndev->flags &IFF_UP )/* can't act on a running interface */ +return -EBUSY ; + +/* Don't allow changing the I/O address */ +if (map->base_addr != ndev->base_addr) { +pr_warn ("%s: can't change I/O address\n" , ndev->name); +return -EOPNOTSUPP ; + } + +/* Don't allow changing the IRQ */ +if (map->irq != ndev->irq) { +pr_warn ("%s: can't change IRQ number %d\n" , ndev->name, ndev->irq); +return -EOPNOTSUPP ; + } + +return 0 ; +} + +static int geth_set_mac_address (struct net_device *ndev,void *p) +{ +struct geth_priv *priv =netdev_priv (ndev); +struct sockaddr *addr = p; + +if (!is_valid_ether_addr (addr->sa_data)) +return -EADDRNOTAVAIL ; + +memcpy (ndev->dev_addr, addr->sa_data, ndev->addr_len); +sunxi_set_umac (priv->base, ndev->dev_addr,0 ); + +return 0 ; +} + +int geth_set_features (struct net_device *ndev,netdev_features_t features) +{ +struct geth_priv *priv =netdev_priv (ndev); + +if (features &NETIF_F_LOOPBACK &&netif_running (ndev)) +sunxi_mac_loopback (priv->base,1 ); +else +sunxi_mac_loopback (priv->base,0 ); + +return 0 ; +} + +#if IS_ENABLED (CONFIG_NET_POLL_CONTROLLER ) +/* Polling receive - used by NETCONSOLE and other diagnostic tools +* to allow network I/O with interrupts disabled. +*/ +static void geth_poll_controller (struct net_device *dev) +{ +disable_irq (dev->irq); +geth_interrupt (dev->irq, dev); +enable_irq (dev->irq); +} +#endif + +static const struct net_device_ops geth_netdev_ops = { + .ndo_init =NULL , + .ndo_open = geth_open, + .ndo_start_xmit = geth_xmit, + .ndo_stop = geth_stop, + .ndo_change_mtu = geth_change_mtu, + .ndo_fix_features = geth_fix_features, + .ndo_set_rx_mode = geth_set_rx_mode, + .ndo_tx_timeout = geth_tx_timeout, + .ndo_do_ioctl = geth_ioctl, + .ndo_set_config = geth_config, +#if IS_ENABLED(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = geth_poll_controller, +#endif + .ndo_set_mac_address = geth_set_mac_address, + .ndo_set_features = geth_set_features, +}; + +static int geth_check_if_running (struct net_device *ndev) +{ +if (!netif_running (ndev)) +return -EBUSY ; +return 0 ; +} + +static int geth_get_sset_count (struct net_device *netdev,int sset) +{ +int len; + +switch (sset) { +case ETH_SS_STATS : + len =0 ; +return len; +default : +return -EOPNOTSUPP ; + } +} + +/*static int geth_ethtool_getsettings(struct net_device *ndev, +struct ethtool_cmd *cmd) +{ +struct geth_priv *priv = netdev_priv(ndev); +struct phy_device *phy = ndev->phydev; +int rc; + +if (phy == NULL) { +netdev_err(ndev, "%s: %s: PHY is not registered\n", +__func__, ndev->name); +return -ENODEV; +} + +if (!netif_running(ndev)) { +pr_err("%s: interface is disabled: we cannot track " +"link speed / duplex setting\n", ndev->name); +return -EBUSY; +} + +cmd->transceiver = XCVR_INTERNAL; +spin_lock_irq(&priv->lock); +//rc = phy_ethtool_gset(phy, cmd); +spin_unlock_irq(&priv->lock); + +return rc; +} + +static int geth_ethtool_setsettings(struct net_device *ndev, +struct ethtool_cmd *cmd) +{ +struct geth_priv *priv = netdev_priv(ndev); +struct phy_device *phy = ndev->phydev; +int rc; + +spin_lock(&priv->lock); +rc = phy_ethtool_sset(phy, cmd); +spin_unlock(&priv->lock); + +return rc; +}*/ + +static void geth_ethtool_getdrvinfo (struct net_device *ndev, +struct ethtool_drvinfo *info) +{ +strlcpy (info->driver,"sunxi_geth" ,sizeof (info->driver)); + +#define DRV_MODULE_VERSION "SUNXI Gbgit driver V1.1" + +strcpy (info->version,DRV_MODULE_VERSION ); + info->fw_version[0 ] ='\0' ; +} + +static const struct ethtool_ops geth_ethtool_ops = { + .begin = geth_check_if_running, +//.get_settings = geth_ethtool_getsettings, +//.set_settings = geth_ethtool_setsettings, + .get_link = ethtool_op_get_link, + .get_pauseparam =NULL , + .set_pauseparam =NULL , + .get_ethtool_stats =NULL , + .get_strings =NULL , + .get_wol =NULL , + .set_wol =NULL , + .get_sset_count = geth_get_sset_count, + .get_drvinfo = geth_ethtool_getdrvinfo, +}; + +/* config hardware resource */ +static int geth_hw_init (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); +struct device_node *np = pdev->dev.of_node; +int ret =0 ; +struct resource *res; +u32 value; +// struct gpio_config cfg; +// const char *gmac_power; +// char power[20]; +// int i; + +#if 1 + priv->phy_ext =EXT_PHY ; +#else + priv->phy_ext =INT_PHY ; +#endif + +/* config memery resource */ + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (unlikely (!res)) { +pr_err ("%s: ERROR: get gmac memory failed" , __func__); +return -ENODEV ; + } + + priv->base =devm_ioremap_resource (&pdev->dev, res); +if (!priv->base) { +pr_err ("%s: ERROR: gmac memory mapping failed" , __func__); +return -ENOMEM ; + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (unlikely (!res)) { +pr_err ("%s: ERROR: get phy memory failed" , __func__); + ret = -ENODEV ; + goto mem_err; + } + + priv->base_phy =devm_ioremap_resource (&pdev->dev, res); +if (unlikely (!priv->base_phy)) { +pr_err ("%s: ERROR: phy memory mapping failed" , __func__); + ret = -ENOMEM ; + goto mem_err; + } + +/* config IRQ */ + ndev->irq =platform_get_irq_byname (pdev,"gmacirq" ); +if (ndev->irq == -ENXIO ) { +pr_err ("%s: ERROR: MAC IRQ not found\n" , __func__); + ret = -ENXIO ; + goto irq_err; + } + + ret =request_irq (ndev->irq, geth_interrupt,IRQF_SHARED ,dev_name (&pdev->dev), ndev); +if (unlikely (ret <0 )) { +pr_err ("Could not request irq %d, error: %d\n" , ndev->irq, ret); + goto irq_err; + } + +/* get gmac rst handle */ +/* +priv->reset = devm_reset_control_get(&pdev->dev, NULL); +if (IS_ERR(priv->reset)) { +pr_err("%s: Get gmac reset control failed!\n", __func__); +return PTR_ERR(priv->reset); +} +*/ +/* config clock */ +/* +priv->geth_clk = of_clk_get_by_name(np, "gmac"); +if (unlikely(!priv->geth_clk || IS_ERR(priv->geth_clk))) { +pr_err("Get gmac clock failed!\n"); +ret = -EINVAL; +goto clk_err; +} + +if (INT_PHY == priv->phy_ext) { +priv->ephy_clk = of_clk_get_by_name(np, "ephy"); +if (unlikely(IS_ERR_OR_NULL(priv->ephy_clk))) { +pr_err("Get ephy clock failed!\n"); +ret = -EINVAL; +goto clk_err; +} +} else { +if (!of_property_read_u32(np, "use-ephy25m", &(priv->use_ephy_clk)) +&& priv->use_ephy_clk) { +priv->ephy_clk = of_clk_get_by_name(np, "ephy"); +if (unlikely(IS_ERR_OR_NULL(priv->ephy_clk))) { +pr_err("Get ephy clk failed!\n"); +ret = -EINVAL; +goto clk_err; +} +} +} +*/ +/* config power regulator */ +/* +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +snprintf(power, 15, "gmac-power%d", i); +ret = of_property_read_string(np, power, &gmac_power); +if (ret) { +priv->gmac_power[i] = NULL; +pr_info("gmac-power%d: NULL\n", i); +continue; +} +priv->gmac_power[i] = regulator_get(NULL, gmac_power); +if (IS_ERR(priv->gmac_power[i])) { +pr_err("gmac-power%d get error!\n", i); +ret = -EINVAL; +goto clk_err; +} +} +} +*/ +/* config other parameters */ +of_get_phy_mode (np, &(priv->phy_interface)); +if (priv->phy_interface !=PHY_INTERFACE_MODE_MII && + priv->phy_interface !=PHY_INTERFACE_MODE_RGMII && + priv->phy_interface !=PHY_INTERFACE_MODE_RMII ) { +pr_err ("Not support phy type!\n" ); + priv->phy_interface =PHY_INTERFACE_MODE_MII ; + } + +if (!of_property_read_u32 (np,"tx-delay" , &value)) + priv->tx_delay = value; + +if (!of_property_read_u32 (np,"rx-delay" , &value)) + priv->rx_delay = value; + +/* config pinctrl */ +/* +if (EXT_PHY == priv->phy_ext) { +priv->phyrst = of_get_named_gpio_flags(np, "phy-rst", 0, (enum of_gpio_flags *)&cfg); +priv->rst_active_low = (cfg.data == OF_GPIO_ACTIVE_LOW) ? 1 : 0; + +if (gpio_is_valid(priv->phyrst)) { +if (gpio_request(priv->phyrst, "phy-rst") < 0) { +pr_err("gmac gpio request fail!\n"); +ret = -EINVAL; +goto pin_err; +} +} + +priv->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); +if (IS_ERR_OR_NULL(priv->pinctrl)) { +pr_err("gmac pinctrl error!\n"); +priv->pinctrl = NULL; +ret = -EINVAL; +goto pin_err; +} +} +*/ +return 0 ; + +//pin_err: +/* +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_put(priv->gmac_power[i]); +} +} +*/ +//clk_err: +// free_irq(ndev->irq, ndev); +irq_err: +devm_iounmap (&pdev->dev, priv->base_phy); +mem_err: +devm_iounmap (&pdev->dev, priv->base); + +return ret; +} + +static void geth_hw_release (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); + +devm_iounmap (&pdev->dev, (priv->base_phy)); +devm_iounmap (&pdev->dev, priv->base); +free_irq (ndev->irq, ndev); +/* +if (priv->geth_clk) +clk_put(priv->geth_clk); + +if (EXT_PHY == priv->phy_ext) { +for (i = 0; i < POWER_CHAN_NUM; i++) { +if (IS_ERR_OR_NULL(priv->gmac_power[i])) +continue; +regulator_put(priv->gmac_power[i]); +} + +if (!IS_ERR_OR_NULL(priv->pinctrl)) +devm_pinctrl_put(priv->pinctrl); + +if (gpio_is_valid(priv->phyrst)) +gpio_free(priv->phyrst); +} + +if (!IS_ERR_OR_NULL(priv->ephy_clk)) +clk_put(priv->ephy_clk); +*/ +} + +/** +* geth_probe +* @pdev: platform device pointer +* Description: the driver is initialized through platform_device. +*/ +static int geth_probe (struct platform_device *pdev) +{ +int ret =0 ; +struct net_device *ndev =NULL ; +struct geth_priv *priv; + +pr_info ("sunxi gmac driver's version: %s\n" ,SUNXI_GMAC_VERSION ); + +#if IS_ENABLED (CONFIG_OF ) + pdev->dev.dma_mask = &geth_dma_mask; + pdev->dev.coherent_dma_mask =DMA_BIT_MASK (32 ); +#endif + + ndev =alloc_etherdev (sizeof (struct geth_priv )); +if (!ndev) { +dev_err (&pdev->dev,"could not allocate device.\n" ); +return -ENOMEM ; + } +SET_NETDEV_DEV (ndev, &pdev->dev); + + priv =netdev_priv (ndev); +platform_set_drvdata (pdev, ndev); + +/* Must set private data to pdev, before call it */ + ret =geth_hw_init (pdev); +if (0 != ret) { +pr_err ("geth_hw_init fail!\n" ); + goto hw_err; + } + +/* setup the netdevice, fill the field of netdevice */ +ether_setup (ndev); + ndev->netdev_ops = &geth_netdev_ops; +netdev_set_default_ethtool_ops (ndev, &geth_ethtool_ops); + ndev->base_addr = (unsigned long )priv->base; + + priv->ndev = ndev; + priv->dev = &pdev->dev; + +/* TODO: support the VLAN frames */ + ndev->hw_features =NETIF_F_SG |NETIF_F_HIGHDMA |NETIF_F_IP_CSUM | +NETIF_F_IPV6_CSUM |NETIF_F_RXCSUM ; + + ndev->features |= ndev->hw_features; + ndev->hw_features |=NETIF_F_LOOPBACK ; + ndev->priv_flags |=IFF_UNICAST_FLT ; + + ndev->watchdog_timeo =msecs_to_jiffies (watchdog); + +netif_napi_add (ndev, &priv->napi, geth_poll,BUDGET ); + +spin_lock_init (&priv->lock); +spin_lock_init (&priv->tx_lock); + +/* The last val is mdc clock ratio */ +sunxi_geth_register ((void *)ndev->base_addr,HW_VERSION ,0x03 ); + + ret =register_netdev (ndev); +if (ret) { +netif_napi_del (&priv->napi); +pr_err ("Error: Register %s failed\n" , ndev->name); + goto reg_err; + } + +/* Before open the device, the mac address should be set */ +geth_check_addr (ndev, mac_str); + +#ifdef CONFIG_GETH_ATTRS +geth_create_attrs (ndev); +#endif +device_create_file (&pdev->dev, &dev_attr_gphy_test); +device_create_file (&pdev->dev, &dev_attr_mii_reg); +device_create_file (&pdev->dev, &dev_attr_loopback_test); +device_create_file (&pdev->dev, &dev_attr_extra_tx_stats); +device_create_file (&pdev->dev, &dev_attr_extra_rx_stats); + +device_enable_async_suspend (&pdev->dev); + +#if IS_ENABLED (CONFIG_PM ) +INIT_WORK (&priv->eth_work, geth_resume_work); +#endif + +return 0 ; + +reg_err: +geth_hw_release (pdev); +hw_err: +platform_set_drvdata (pdev,NULL ); +free_netdev (ndev); + +return ret; +} + +static int geth_remove (struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct geth_priv *priv =netdev_priv (ndev); + +device_remove_file (&pdev->dev, &dev_attr_gphy_test); +device_remove_file (&pdev->dev, &dev_attr_mii_reg); +device_remove_file (&pdev->dev, &dev_attr_loopback_test); +device_remove_file (&pdev->dev, &dev_attr_extra_tx_stats); +device_remove_file (&pdev->dev, &dev_attr_extra_rx_stats); + +netif_napi_del (&priv->napi); +unregister_netdev (ndev); +geth_hw_release (pdev); +platform_set_drvdata (pdev,NULL ); +free_netdev (ndev); + +return 0 ; +} + +static const struct of_device_id geth_of_match[] = { + {.compatible ="allwinner,sunxi-gmac" ,}, + {}, +}; +MODULE_DEVICE_TABLE (of, geth_of_match); + +static struct platform_driver geth_driver = { + .probe = geth_probe, + .remove = geth_remove, + .driver = { + .name ="sunxi-gmac" , + .owner =THIS_MODULE , + .pm = &geth_pm_ops, + .of_match_table = geth_of_match, + }, +}; +module_platform_driver (geth_driver); + +#ifdef MODULE +static int __init set_mac_addr (char *str) +{ +char *p = str; + +if (str &&strlen (str)) +memcpy (mac_str, p,18 ); + +return 0 ; +} +__setup ("mac_addr=" , set_mac_addr); +#endif + +MODULE_DESCRIPTION ("Allwinner Gigabit Ethernet driver" ); +MODULE_AUTHOR ("fuzhaoke <[email protected]>" ); +MODULE_LICENSE ("Dual BSD/GPL" );drivers/net/ethernet/allwinnertmp/sunxi-gmac.h new file +258
-0@@ -0,0 +1,258 @@ +/* +* linux/drivers/net/ethernet/allwinner/sunxi_gmac.h +* Lines of this file are not shown. View the raw message.
drivers/net/phy/realtek.c +0
-0@@ -338,7 +338,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)The rest of this diff is not shown. View the raw message.
Quoted 9 lines
drivers/net/phy/realtek.c
Quoted 8 lines
drivers/net/phy/realtek.c +1
-1Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
--
Best Regards
Guo Ren
ML: https://lore.kernel.org/linux-csky/
Part of the diff is not shown here. View the raw message.
Jernej Škrabec
maintainerRe: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
Hi!
Dne nedelja, 06. junij 2021 ob 17:32:22 CEST je Guo Ren napisal(a):
Quoted 3 lines
,
On Sun, Jun 6, 2021 at 6:50 PM Andre Przywara <[email protected]>
Quoted 26 lines · wrote:
Quoted 19 lines
On Sun, 6 Jun 2021 09:04:09 +0000
[email protected] wrote:Hi,
Quoted 4 lines
From: liush <[email protected]>
This is a temporary driver, only guaranteed to work on allwinner D1. In order to ensure the developer's demand for network usage.
That looks like some Allwinner BSP driver, please don't endorse code of this quality (just look at all that commented code and the attempt for compile-time configuration).
Quoted 5 lines
It only could work at 1Gps mode.
The correct gmac driver should follow (I guess)
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.cQuoted 6 lines
Quoted 2 lines
If anyone is familiar with it and can help porting, I would be very grateful.
Have you tried compiling and using that driver? Ideally it should just work, Linux drivers are meant to be portable, by design. And the driver is already enabled by
COMPILE_TEST.
Quoted 5 lines
It still needs some work with
dwmac-sun8i.cglue layer, eg:
tx/rx-delay setting, clk & pinmux drivers.The patch is just to help people using D1 with GMAC temporarily with network function.
It should be marked "DO NOT MERGE" or similar then.
Best regards,
Jernej
Quoted 27 lines
Quoted 4 lines
But I guess you need some extra care to make the non-coherent DMA work? I haven't looked in detail, but are those new CMOs hooked into the generic DMA framework?
Yes, we have the simliar principle with arm & csky for non-coherent:
- Using PTE attributes setting Using PTE attributes to support_PAGE_IOREMAP&_PAGE_WRITECOMBINE
- Using CMO instructions deal SYNC_DMA_FOR_CPU/DEVICE.Quoted 17 lines
Cheers,
AndreQuoted 14 lines
Signed-off-by Liu Shaohua <[email protected]>Tested-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc Maxime Ripard <[email protected]>Cc Corentin Labbe <[email protected]>Cc Samuel Holland <[email protected]>Cc Icenowy Zheng <[email protected]>Cc LABBE Corentin <[email protected]>Cc Michael Walle <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Signed-off-by Guo Ren <[email protected]>
Re: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
Quoted 34 lines · Jernej Škrabec
Hi!
Dne nedelja, 06. junij 2021 ob 17:32:22 CEST je Guo Ren napisal(a):
Quoted 3 lines
,
On Sun, Jun 6, 2021 at 6:50 PM Andre Przywara <[email protected]>
Quoted 26 lines · wrote:
Quoted 25 lines
On Sun, 6 Jun 2021 09:04:09 +0000
[email protected] wrote:Hi,
Quoted 4 lines
From: liush <[email protected]>
This is a temporary driver, only guaranteed to work on allwinner D1. In order to ensure the developer's demand for network usage.
That looks like some Allwinner BSP driver, please don't endorse code of this quality (just look at all that commented code and the attempt for compile-time configuration).
Quoted 7 lines
It only could work at 1Gps mode.
The correct gmac driver should follow (I guess)
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.cIf anyone is familiar with it and can help porting, I would be very grateful.
Have you tried compiling and using that driver? Ideally it should just work, Linux drivers are meant to be portable, by design. And the driver is already enabled by
COMPILE_TEST.
Quoted 7 lines
Quoted 5 lines
It still needs some work with
dwmac-sun8i.cglue layer, eg:
tx/rx-delay setting, clk & pinmux drivers.The patch is just to help people using D1 with GMAC temporarily with network function.
It should be marked "DO NOT MERGE" or similar then.
Yes, thx for reminding. I'll fix it next time.
Quoted 34 lines
Best regards,
JernejQuoted 27 lines
Quoted 4 lines
But I guess you need some extra care to make the non-coherent DMA work? I haven't looked in detail, but are those new CMOs hooked into the generic DMA framework?
Yes, we have the simliar principle with arm & csky for non-coherent:
- Using PTE attributes setting Using PTE attributes to support_PAGE_IOREMAP&_PAGE_WRITECOMBINE
- Using CMO instructions deal SYNC_DMA_FOR_CPU/DEVICE.Quoted 17 lines
Cheers,
AndreQuoted 14 lines
Signed-off-by Liu Shaohua <[email protected]>Tested-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc Maxime Ripard <[email protected]>Cc Corentin Labbe <[email protected]>Cc Samuel Holland <[email protected]>Cc Icenowy Zheng <[email protected]>Cc LABBE Corentin <[email protected]>Cc Michael Walle <[email protected]>Cc Chen-Yu Tsai <[email protected]>Cc Maxime Ripard <[email protected]>Cc Wei Fu <[email protected]>Cc Wei Wu <[email protected]>Signed-off-by Guo Ren <[email protected]>
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Arnd Bergmann
maintainerRe: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
In reply to [email protected]arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 10 lines · On Sun, Jun 6, 2021 at 11:04 AM <[email protected]> wrote:
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/init root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23";
These are not board specific options, they should be set by the bootloader according to the network environment. It clearly doens't belong into this patch .
Quoted 17 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +0
-0stdout-path = &serial0; };arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +6
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030 0x00 0x04>; + interrupts-extended = <&plic 0x3e 0x04>; + interrupt-names = "gmacirq";
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 98
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +10
-0+ device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + };
Before you add this in the dts file, the properties need to be documented in the binding file. The "allwinner,sunxi-gmac" identifier does not appear to be specific enough here, and the properties don't match what dwmac uses, which would make it unnecessarily hard to change to the other driver later on without breaking compatibility to old dtb files.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 8
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +9
-0+++ b/drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c@@ -0,0 +1,690 @@ +/* + * linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c + * + * Copyright © 2016-2018, fuzhaoke + * Author: fuzhaoke <[email protected]> + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license.
Are you sure this is the correct copyright information and "fuzhaoke" is the copyright holder for this file? If this is derived from either the designware
code or the Linux stmmac driver, the authors should be mentioned, and the license be compatible with the original license terms.
Andre already commented on the driver quality and code duplication, those are also show-stoppers, but the unclear license terms and dt binding compatibility are even stronger reasons to not get anywhere close to this driver.
Arnd
Jernej Škrabec
maintainerRe: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
Dne nedelja, 06. junij 2021 ob 18:16:44 CEST je Arnd Bergmann napisal(a):
Quoted 77 lines · On Sun, Jun 6, 2021 at 11:04 AM <[email protected]> wrote:
Quoted 13 lines
(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsindex cd9f7c9..31b681d 100644arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/initQuoted 2 lines
root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23";
These are not board specific options, they should be set by the bootloader according to the network environment. It clearly doens't belong into this patch .
Quoted 23 lines
stdout-path = &serial0; };(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiindex 11cd938..d317e19 100644arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +4
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030
0x000x04>; + interrupts-extended = <&plic0x3e0x04>;arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +1
-0+ interrupt-names = "gmacirq";arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 98
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +10
-0+ device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + };Before you add this in the dts file, the properties need to be documented in the binding file. The "allwinner,sunxi-gmac" identifier does not appear to be specific enough here, and the properties don't match what dwmac uses, which would make it unnecessarily hard to change to the other driver later on without breaking compatibility to old dtb files.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 8
Quoted 10 lines
+++
b/drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.carch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +8
-0@@ -0,0 +1,690 @@ +/* + * linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c + * + * Copyright © 2016-2018, fuzhaoke + * Author: fuzhaoke <[email protected]> + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license.Are you sure this is the correct copyright information and "fuzhaoke" is the copyright holder for this file? If this is derived from either the designware
code or the Linux stmmac driver, the authors should be mentioned, and the license be compatible with the original license terms.
Quoted 4 lines
Andre already commented on the driver quality and code duplication, those are also show-stoppers, but the unclear license terms and dt binding compatibility are even stronger reasons to not get anywhere close to this driver.
I got impression that this patch is not meant to be merged and it's forward ported from vendor kernel as a stop gap measure for developers until proper mainline ethernet driver is developed.
Best regards,
Jernej
Re: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
Quoted 79 lines · Jernej Škrabec
Dne nedelja, 06. junij 2021 ob 18:16:44 CEST je Arnd Bergmann napisal(a):
Quoted 77 lines · On Sun, Jun 6, 2021 at 11:04 AM <[email protected]> wrote:
Quoted 13 lines
(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtsindex cd9f7c9..31b681d 100644arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/initQuoted 2 lines
root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23";
These are not board specific options, they should be set by the bootloader according to the network environment. It clearly doens't belong into this patch .
Quoted 23 lines
stdout-path = &serial0; };(quoted diff) +0
-0
b/arch/riscv/boot/dts/allwinner/allwinner-d1.dtsiindex 11cd938..d317e19 100644arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +4
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030
0x000x04>; + interrupts-extended = <&plic0x3e0x04>;arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +1
-0+ interrupt-names = "gmacirq";arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 98
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +10
-0+ device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + };Before you add this in the dts file, the properties need to be documented in the binding file. The "allwinner,sunxi-gmac" identifier does not appear to be specific enough here, and the properties don't match what dwmac uses, which would make it unnecessarily hard to change to the other driver later on without breaking compatibility to old dtb files.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 8
Quoted 10 lines
+++
b/drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.carch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +8
-0@@ -0,0 +1,690 @@ +/* + * linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c + * + * Copyright © 2016-2018, fuzhaoke + * Author: fuzhaoke <[email protected]> + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license.Are you sure this is the correct copyright information and "fuzhaoke" is the copyright holder for this file? If this is derived from either the designware
code or the Linux stmmac driver, the authors should be mentioned, and the license be compatible with the original license terms.
Quoted 8 lines
Quoted 4 lines
Andre already commented on the driver quality and code duplication, those are also show-stoppers, but the unclear license terms and dt binding compatibility are even stronger reasons to not get anywhere close to this driver.
I got impression that this patch is not meant to be merged and it's forward ported from vendor kernel as a stop gap measure for developers until proper mainline ethernet driver is developed.
Yes
Quoted 7 lines
Best regards,
Jernej
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Re: [RFC PATCH v2 11/11] riscv: soc: Allwinner D1 GMAC driver only for temp use
In reply to Arnd BergmannSorry, wast your time reviewing the patch. It's not ready to merge, just for the test.
Quoted 74 lines · Arnd Bergmann
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts line 14
Quoted 10 lines · On Sun, Jun 6, 2021 at 11:04 AM <[email protected]> wrote:
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +1
-1@@ -11,7 +11,7 @@ compatible = "allwinner,d1-nezha-kit"; chosen { - bootargs = "console=ttyS0,115200"; + bootargs = "console=ttyS0,115200 rootwait init=/sbin/init root=/dev/nfs rw nfsroot=192.168.101.200:/tmp/rootfs_nfs,v3,tcp,nolock ip=192.168.101.23";These are not board specific options, they should be set by the bootloader according to the network environment. It clearly doens't belong into this patch .
Quoted 17 lines
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts +0
-0stdout-path = &serial0; };arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +6
-0@@ -80,5 +80,21 @@ clocks = <&dummy_apb>; status = "disabled"; }; + + eth@4500000 { + compatible = "allwinner,sunxi-gmac"; + reg = <0x00 0x4500000 0x00 0x10000 0x00 0x3000030 0x00 0x04>; + interrupts-extended = <&plic 0x3e 0x04>; + interrupt-names = "gmacirq";arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 98
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +10
-0+ device_type = "gmac0"; + phy-mode = "rgmii"; + use_ephy25m = <0x01>; + tx-delay = <0x03>; + rx-delay = <0x03>; + gmac-power0; + gmac-power1; + gmac-power2; + status = "okay"; + };Before you add this in the dts file, the properties need to be documented in the binding file. The "allwinner,sunxi-gmac" identifier does not appear to be specific enough here, and the properties don't match what dwmac uses, which would make it unnecessarily hard to change to the other driver later on without breaking compatibility to old dtb files.
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi line 8
Quoted 10 lines
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi +9
-0+++ b/drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c@@ -0,0 +1,690 @@ +/* + * linux/drivers/net/ethernet/allwinner/sunxi_gmac_ops.c + * + * Copyright © 2016-2018, fuzhaoke + * Author: fuzhaoke <[email protected]> + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license.Are you sure this is the correct copyright information and "fuzhaoke" is the copyright holder for this file? If this is derived from either the designware
code or the Linux stmmac driver, the authors should be mentioned, and the license be compatible with the original license terms.Andre already commented on the driver quality and code duplication, those are also show-stoppers, but the unclear license terms and dt binding compatibility are even stronger reasons to not get anywhere close to this driver.
Arnd
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Jernej Škrabec
maintainerHi!
Dne nedelja, 06. junij 2021 ob 11:03:55 CEST je [email protected] napisal(a):
Quoted 41 lines
From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE which not mentioned in spec.Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has no conflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and setup custom PTE attributes in a global struct variable during boot stage. Also it needs define customprotection_mapin linux/mm.
- cmo: We need deal withdma_sync&icache_sync&__vdso_icache_sync. In this patchset, I just show you how T-HEAD C9xx work, and seems Atish is working for the DMA infrustructure, please let me know the idea.
- soc: Add allwinner gmac driver & dts &Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000
-n Linux -darch/riscv/boot/ImageuImage - Download newest opensbi [2], build with [3], and get fw_dynamic.bin - Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.
- Plugin the TF card and power on D1.
Quoted 6 lines
Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]Link:
https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
[3]
Some patches are marked with v2 and some V5. It's very confusing. Mark them with same version in next revision.
Best regards,
Jernej
Quoted 67 lines
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usageGuo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig optionliush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi create mode 100644 arch/riscv/mm/dma-mapping.c create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
V5 is not related to the patch series.
Quoted 129 lines · Jernej Škrabec
Hi!
Dne nedelja, 06. junij 2021 ob 11:03:55 CEST je [email protected] napisal(a):
Quoted 41 lines
From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE which not mentioned in spec.Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has no conflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and setup custom PTE attributes in a global struct variable during boot stage. Also it needs define customprotection_mapin linux/mm.
- cmo: We need deal withdma_sync&icache_sync&__vdso_icache_sync. In this patchset, I just show you how T-HEAD C9xx work, and seems Atish is working for the DMA infrustructure, please let me know the idea.
- soc: Add allwinner gmac driver & dts &Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000
-n Linux -darch/riscv/boot/ImageuImage - Download newest opensbi [2], build with [3], and get fw_dynamic.bin - Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.
- Plugin the TF card and power on D1.Quoted 6 lines
Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]Link:
https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
[3]Some patches are marked with v2 and some V5. It's very confusing. Mark them with same version in next revision.
Best regards,
JernejQuoted 67 lines
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usageGuo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig optionliush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi create mode 100644 arch/riscv/mm/dma-mapping.c create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Jernej Škrabec
maintainerDne nedelja, 06. junij 2021 ob 18:54:05 CEST je Guo Ren napisal(a):
Quoted 1 line
V5 is not related to the patch series.
Don't top post.
If that's the case, then your e-mail client messed things up. I got V5 patches in the same thread as board enablement patches and so did mailing list [1].
Best regards,
Jernej
[1] https://lore.kernel.org/linux-sunxi/
CAJF2gTQ1yvSNthJ2yJkqaYGaJ6OYmf0vbG=hm4ocgnw4DiZbOw@mail.gmail.com/T/#t
Quoted 2 lines
On Mon, Jun 7, 2021 at 12:29 AM Jernej Škrabec <[email protected]>
Quoted 3 lines · wrote:
Quoted 3 lines
Hi!
Dne nedelja, 06. junij 2021 ob 11:03:55 CEST je [email protected]
napisal(a):
Quoted 142 lines
Quoted 142 lines
Quoted 53 lines
From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has
two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE whichnot mentioned in spec.
Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been
tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has noconflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and
setup custom PTE attributes in a global struct variable during boot stage. Also it needs define custom
protection_mapin linux/mm.- cmo: We need deal with
dma_sync&icache_sync&__vdso_icache_sync.In this patchset, I just show you how T-HEAD C9xx work, and seems Atish
is working for the DMA infrustructure, please let me know the idea.- soc: Add allwinner gmac driver & dts &
Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000-n Linux -d
arch/riscv/boot/ImageuImage - Download newest opensbi [2], build with [3], and get fw_dynamic.bin - Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.Quoted 7 lines
- Plugin the TF card and power on D1.
Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]Link:
https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
[3]Some patches are marked with v2 and some V5. It's very confusing. Mark them
with same version in next revision.Best regards,
JernejQuoted 74 lines
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usageGuo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig optionliush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240++++++++++++++++++++
drivers/net/ethernet/allwinnertmp/sunxi-gmac.h|
258 +++drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsicreate
mode 100644arch/riscv/mm/dma-mapping.ccreate mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
Quoted 8 lines · Jernej Škrabec
Dne nedelja, 06. junij 2021 ob 18:54:05 CEST je Guo Ren napisal(a):
Quoted 1 line
V5 is not related to the patch series.
Don't top post.
If that's the case, then your e-mail client messed things up. I got V5 patches in the same thread as board enablement patches and so did mailing list [1].
I made mistake that make two patchset mixed in my linux directory.
git format-patch -11
git send-email *.patch
But there are still some last posted patches in *.patch.
I'll prevent it in the next patchset version.
Quoted 160 lines
Best regards,
Jernej[1] https://lore.kernel.org/linux-sunxi/
CAJF2gTQ1yvSNthJ2yJkqaYGaJ6OYmf0vbG=hm4ocgnw4DiZbOw@mail.gmail.com/T/#tQuoted 2 lines
On Mon, Jun 7, 2021 at 12:29 AM Jernej Škrabec <[email protected]>
Quoted 3 lines · wrote:
Quoted 3 lines
Hi!
Dne nedelja, 06. junij 2021 ob 11:03:55 CEST je [email protected]
napisal(a):
Quoted 142 lines
Quoted 142 lines
Quoted 53 lines
From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has
two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE whichnot mentioned in spec.
Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been
tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has noconflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and
setup custom PTE attributes in a global struct variable during boot stage. Also it needs define custom
protection_mapin linux/mm.- cmo: We need deal with
dma_sync&icache_sync&__vdso_icache_sync.In this patchset, I just show you how T-HEAD C9xx work, and seems Atish
is working for the DMA infrustructure, please let me know the idea.- soc: Add allwinner gmac driver & dts &
Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000-n Linux -d
arch/riscv/boot/ImageuImage - Download newest opensbi [2], build with [3], and get fw_dynamic.bin - Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.Quoted 7 lines
- Plugin the TF card and power on D1.
Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]Link:
https://github.com/riscv/opensbi/blob/master/docs/platform/thead-c9xx.md
[3]Some patches are marked with v2 and some V5. It's very confusing. Mark them
with same version in next revision.Best regards,
JernejQuoted 74 lines
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usageGuo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig optionliush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240++++++++++++++++++++
drivers/net/ethernet/allwinnertmp/sunxi-gmac.h|
258 +++drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1-nezha-kit.dtscreate mode 100644
arch/riscv/boot/dts/allwinner/allwinner-d1.dtsicreate
mode 100644arch/riscv/mm/dma-mapping.ccreate mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Quoted 69 lines
-----Original Message-----
From: [email protected] <[email protected]>
Sent: 06 June 2021 14:34
To: [email protected]; Anup Patel <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Cc: [email protected]; [email protected]; linux- [email protected]; [email protected]; Guo Ren <[email protected]>
Subject: [RFC PATCH v2 00/11] riscv: AddDMA_COHERENTsupport for Allwinner D1From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE which not mentioned in spec.Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has no conflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and setup custom PTE attributes in a global struct variable during boot stage. Also it needs define customprotection_mapin linux/mm.
- cmo: We need deal withdma_sync&icache_sync&__vdso_icache_sync. In this patchset, I just show you how T-HEAD C9xx work, and seems Atish is working for the DMA infrustructure, please let me know the idea.
- soc: Add allwinner gmac driver & dts &Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000-
n Linux -darch/riscv/boot/ImageuImage
- Download newest opensbi [2], build with [3], and get fw_dynamic.bin
- Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.
- Plugin the TF card and power on D1.Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]c9xx.md [3]
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usage
Quoted 11 lines
Guo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig option
The series cover letter says DMA_COHERENT support but it is doing lot of stuff not related to DMA.
Please keep the first three patches separate. They belong to your ASID series.
I also dislike the fact that you are continuously sending SBI DMA sync patches without any discussion on the UnixPlatform mailing list for SBI spec changes.
Regards,
Anup
Quoted 53 lines
liush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha- kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi create mode 100644 arch/riscv/mm/dma-mapping.c create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h--
2.7.4
Hi Anup,
Quoted 82 lines · Anup Patel
Quoted 70 lines
-----Original Message-----
From: [email protected] <[email protected]>
Sent: 06 June 2021 14:34
To: [email protected]; Anup Patel <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Cc: [email protected]; [email protected]; linux- [email protected]; [email protected]; Guo Ren <[email protected]>
Subject: [RFC PATCH v2 00/11] riscv: AddDMA_COHERENTsupport for Allwinner D1From: Guo Ren <[email protected]>
The RISC-V ISA doesn't yet specify how to query or modify PMAs, so let vendors define the custom properties of memory regions in PTE.
This patchset helps SOC vendors to support their own custom interconnect coherent solution with PTE attributes.
For example, allwinner D1[1] uses T-HEAD C906 as main processor, C906 has two modes in MMU:
- Compatible mode, the same as the definitions in spec.
- Enhanced mode, add customDMA_COHERENTattribute bits in PTE which not mentioned in spec.Allwinner D1 needs the enhanced mode to support the DMA type device with non-coherent interconnect in its SOC. C906 uses BITS(63 - 59) as custom attribute bits in PTE.
The patchset contain 4 parts (asid, pgtable, cmo, soc) which have been tested on D1:
- asid: T-HEAD C906 of D1 contains full asid hw facilities which has no conflict with RISC-V spec, and hope these patches soon could be approved.
- pgtable: Using a image-hdr to pass vendor specific information and setup custom PTE attributes in a global struct variable during boot stage. Also it needs define customprotection_mapin linux/mm.
- cmo: We need deal withdma_sync&icache_sync&__vdso_icache_sync. In this patchset, I just show you how T-HEAD C9xx work, and seems Atish is working for the DMA infrustructure, please let me know the idea.
- soc: Add allwinner gmac driver & dts &Kconfigfor sunxi test.The patchset could work with linux-5.13-rc4, here is the steps for D1:
- Download linux-5.13-rc4 and apply the patchset
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
- make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image modules dtbs
- mkimage -A riscv -O linux -T kernel -C none -a0x00200000-e0x00200000-
n Linux -darch/riscv/boot/ImageuImage
- Download newest opensbi [2], build with [3], and get fw_dynamic.bin
- Copy uImage, fw_dynamic.bin, allwinner-d1-nezha-kit.dtb into boot partition of TF card.
- Plugin the TF card and power on D1.Link https://linux-sunxi.org/D1 [1]Link https://github.com/riscv/opensbi branch:master [2]c9xx.md [3]
Changes since v1:
- Rebase on linux-5.13-rc4
- Support defconfig for different PTE attributes
- Support C906icache_sync
- Add Allwinner D1 dts &Kconfig& gmac for testing
- Add asid optimization for D1 usageQuoted 11 lines
Guo Ren (10):
riscv: asid: Use global mappings for kernel pages
riscv: asid: Add ASID-based tlbflushing methods
riscv: asid: Optimize tlbflush coding convention
riscv: pgtable: Fixup_PAGE_CHG_MASKusage
riscv: pgtable: Add customprotection_mapinit
riscv: pgtable: AddDMA_COHERENTwith custom PTE attributes
riscv: cmo: Add dma-noncoherency support
riscv: cmo: Add vendor custom icache sync
riscv: soc: Initial DTS for Allwinner D1 NeZha board
riscv: soc: Add Allwinner SoC kconfig option
Quoted 5 lines
The series cover letter says
DMA_COHERENTsupport but it is doing lot of stuff not related to DMA.Please keep the first three patches separate. They belong to your ASID series.
I just want to give out a whole view of how allwinner D1 works, which could help soc folks run their mini system.
Christoph Hellwig has helped to update the ASID series, and I've given the tested-by on my hardware 4*910 SMP & 906 D1
https://lore.kernel.org/linux-riscv/[email protected]/T/#t
Ok, you won't see it in the next version patchset.
Quoted 4 lines
I also dislike the fact that you are continuously sending SBI DMA sync patches without any discussion on the UnixPlatform mailing list for SBI spec changes.
SBI DMA sync is not critical for us, I could follow your definition when you are ready. Even CBO trap emulation is okay for me.
Quoted 58 lines
Regards,
AnupQuoted 53 lines
liush (1):
riscv: soc: Allwinner D1 GMAC driver only for temp usearch/riscv/Kconfig | 9 + arch/riscv/Kconfig.socs | 12 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/allwinner/Makefile | 2 + .../boot/dts/allwinner/allwinner-d1-nezha-kit.dts | 29 + arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi | 100 + arch/riscv/configs/defconfig | 1 + arch/riscv/include/asm/cacheflush.h | 48 +- arch/riscv/include/asm/mmu_context.h | 2 + arch/riscv/include/asm/pgtable-64.h | 8 +- arch/riscv/include/asm/pgtable-bits.h | 20 +- arch/riscv/include/asm/pgtable.h | 44 +- arch/riscv/include/asm/sbi.h | 15 + arch/riscv/include/asm/soc.h | 1 + arch/riscv/include/asm/tlbflush.h | 22 + arch/riscv/include/asm/vendorid_list.h | 1 + arch/riscv/kernel/sbi.c | 19 + arch/riscv/kernel/soc.c | 22 + arch/riscv/kernel/vdso/flush_icache.S | 33 +- arch/riscv/mm/Makefile | 1 + arch/riscv/mm/cacheflush.c | 3 +- arch/riscv/mm/context.c | 2 +- arch/riscv/mm/dma-mapping.c | 53 + arch/riscv/mm/init.c | 26 + arch/riscv/mm/tlbflush.c | 57 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/allwinnertmp/Kconfig | 17 + drivers/net/ethernet/allwinnertmp/Makefile | 7 + drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c | 690 ++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.c | 2240 ++++++++++++++++++++ drivers/net/ethernet/allwinnertmp/sunxi-gmac.h | 258 +++ drivers/net/phy/realtek.c | 2 +- mm/mmap.c | 4 + 34 files changed, 3714 insertions(+), 37 deletions(-) create mode 100644 arch/riscv/boot/dts/allwinner/Makefile create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1-nezha- kit.dts create mode 100644 arch/riscv/boot/dts/allwinner/allwinner-d1.dtsi create mode 100644 arch/riscv/mm/dma-mapping.c create mode 100644 drivers/net/ethernet/allwinnertmp/Kconfig create mode 100644 drivers/net/ethernet/allwinnertmp/Makefile create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac-ops.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.c create mode 100644 drivers/net/ethernet/allwinnertmp/sunxi-gmac.h--
2.7.4
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/